├── .laya ├── compile.js ├── launch.json ├── publish.js ├── publish_oppogame.js ├── publish_xmgame.js └── settings.json ├── bin ├── DP1.png ├── fileconfig.json ├── game.js ├── game.json ├── index.html ├── index.js ├── joystickView.json ├── js │ └── bundle.js ├── libs │ ├── bytebuffer.js │ ├── domparserinone.js │ ├── laya.ani.js │ ├── laya.bdmini.js │ ├── laya.core.js │ ├── laya.d3.js │ ├── laya.d3Plugin.js │ ├── laya.debugtool.js │ ├── laya.device.js │ ├── laya.effect.js │ ├── laya.html.js │ ├── laya.particle.js │ ├── laya.pathfinding.js │ ├── laya.physics.js │ ├── laya.physics3D.js │ ├── laya.physics3D.runtime.js │ ├── laya.physics3D.wasm.js │ ├── laya.physics3D.wasm.wasm │ ├── laya.quickgamemini.js │ ├── laya.tiledmap.js │ ├── laya.ui.js │ ├── laya.wxmini.js │ ├── laya.xmmini.js │ └── worker.js ├── mainView.json ├── project.config.json ├── project.swan.json ├── res │ └── atlas │ │ └── .rec ├── swan-game-adapter.js ├── tankke.png ├── ui.json ├── unpack.json ├── version.json ├── weapp-adapter.js └── yangan.png ├── joystick.laya ├── laya ├── .laya ├── assets │ ├── DP1.png │ ├── tankke.png │ └── yangan.png ├── ignore.cfg └── pages │ ├── joystickView.scene │ └── mainView.scene ├── libs ├── LayaAir.d.ts ├── layaAir.minigame.d.ts ├── union.d.ts └── wx.d.ts ├── src ├── GameConfig.ts ├── JoyStick.ts ├── Main.ts └── ui │ └── layaMaxUI.ts └── tsconfig.json /.laya/compile.js: -------------------------------------------------------------------------------- 1 | // v1.0.0 2 | //是否使用IDE自带的node环境和插件,设置false后,则使用自己环境(使用命令行方式执行) 3 | let useIDENode = process.argv[0].indexOf("LayaAir") > -1 ? true : false; 4 | //获取Node插件和工作路径 5 | let ideModuleDir = useIDENode ? process.argv[1].replace("gulp\\bin\\gulp.js", "").replace("gulp/bin/gulp.js", "") : ""; 6 | let workSpaceDir = useIDENode ? process.argv[2].replace("--gulpfile=", "").replace("\\.laya\\compile.js", "").replace("/.laya/compile.js", "") : "./../"; 7 | 8 | //引用插件模块 9 | let gulp = require(ideModuleDir + "gulp"); 10 | let browserify = require(ideModuleDir + "browserify"); 11 | let source = require(ideModuleDir + "vinyl-source-stream"); 12 | let tsify = require(ideModuleDir + "tsify"); 13 | 14 | // 如果是发布时调用编译功能,增加prevTasks 15 | let prevTasks = ""; 16 | if (global.publish) { 17 | prevTasks = ["loadConfig"]; 18 | } 19 | 20 | //使用browserify,转换ts到js,并输出到bin/js目录 21 | gulp.task("compile", prevTasks, function () { 22 | // 发布时调用编译功能,判断是否点击了编译选项 23 | if (global.publish && !global.config.compile) { 24 | return; 25 | } else if (global.publish && global.config.compile) { 26 | // 发布时调用编译,workSpaceDir使用publish.js里的变量 27 | workSpaceDir = global.workSpaceDir; 28 | } 29 | return browserify({ 30 | basedir: workSpaceDir, 31 | //是否开启调试,开启后会生成jsmap,方便调试ts源码,但会影响编译速度 32 | debug: true, 33 | entries: ['src/Main.ts'], 34 | cache: {}, 35 | packageCache: {} 36 | }) 37 | //使用tsify插件编译ts 38 | .plugin(tsify) 39 | .bundle() 40 | //使用source把输出文件命名为bundle.js 41 | .pipe(source('bundle.js')) 42 | //把bundle.js复制到bin/js目录 43 | .pipe(gulp.dest(workSpaceDir + "/bin/js")); 44 | }); -------------------------------------------------------------------------------- /.laya/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2.0", 3 | "configurations": [ 4 | { 5 | "name": "layaAir", 6 | "type": "chrome", 7 | "request": "launch", 8 | "file": "${workspaceRoot}/bin/index.html", 9 | "runtimeExecutable": "${execPath}", 10 | "useBuildInServer": true, 11 | "sourceMaps": true, 12 | "webRoot": "${workspaceRoot}", 13 | "port": 9222, 14 | "fixedPort":false, 15 | "sourceMapPathOverrides": { 16 | "src/*": "${workspaceRoot}/src/*" 17 | } 18 | }, 19 | { 20 | "name": "chrome调试", 21 | "type": "chrome", 22 | "request": "launch", 23 | "file": "${workspaceRoot}/bin/index.html", 24 | // "换成自己的谷歌安装路径,": 比如 25 | //window 默认安装路径为: "C:/Program Files (x86)/Google/Chrome/Application/chrome.exe" 26 | //mac 系统上的默认安装路径为 "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome"; 27 | // "runtimeExecutable": "C:/Program Files (x86)/Google/Chrome/Application/chrome.exe", 28 | "runtimeArgs": [ 29 | "--allow-file-access-from-files", 30 | "--allow-file-access-frome-files", 31 | " --disable-web-security" 32 | ], 33 | "sourceMaps": true, 34 | "webRoot": "${workspaceRoot}", 35 | //假如谷歌调试报userDataDir不可用,请把谷歌安装路径取得管理员权限,或者更换${tmpdir}为其他可以读写的文件夹,也可以删除。 36 | "userDataDir": "${workspaceRoot}/.laya/chrome", 37 | "fixedPort":false, 38 | "sourceMapPathOverrides": { 39 | "src/*": "${workspaceRoot}/src/*" 40 | } 41 | } 42 | ] 43 | } -------------------------------------------------------------------------------- /.laya/publish.js: -------------------------------------------------------------------------------- 1 | // v1.2.0 2 | //是否使用IDE自带的node环境和插件,设置false后,则使用自己环境(使用命令行方式执行) 3 | const useIDENode = process.argv[0].indexOf("LayaAir") > -1 ? true : false; 4 | //获取Node插件和工作路径 5 | let ideModuleDir = useIDENode ? process.argv[1].replace("gulp\\bin\\gulp.js", "").replace("gulp/bin/gulp.js", "") : ""; 6 | let workSpaceDir = useIDENode ? process.argv[2].replace("--gulpfile=", "").replace("\\.laya\\publish.js", "").replace("/.laya/publish.js", "") + "/" : "./../"; 7 | 8 | //引用插件模块 9 | const gulp = require(ideModuleDir + "gulp"); 10 | const fs = require("fs"); 11 | const path = require("path"); 12 | const uglify = require(ideModuleDir + "gulp-uglify"); 13 | const jsonminify = require(ideModuleDir + "gulp-jsonminify"); 14 | const image = require(ideModuleDir + "gulp-image"); 15 | const rev = require(ideModuleDir + "gulp-rev"); 16 | const revdel = require(ideModuleDir + "gulp-rev-delete-original"); 17 | const revCollector = require(ideModuleDir + 'gulp-rev-collector'); 18 | const del = require(ideModuleDir + "del"); 19 | const requireDir = require(ideModuleDir + 'require-dir'); 20 | 21 | global.ideModuleDir = ideModuleDir; 22 | global.workSpaceDir = workSpaceDir; 23 | 24 | // 结合compile.js使用 25 | global.publish = true; 26 | const fileList = ["compile.js", "publish_xmgame.js", "publish_oppogame.js"]; 27 | requireDir('./', { 28 | filter: function (fullPath) { 29 | // 只用到了compile.js和publish.js 30 | if (fileList.includes(path.basename(fullPath))) { 31 | return true; 32 | } else { 33 | return false; 34 | } 35 | } 36 | }); 37 | 38 | // 清理临时文件夹,加载配置 39 | let config, 40 | releaseDir, 41 | platform, 42 | isOpendataProj = false; 43 | gulp.task("loadConfig", function () { 44 | platform = "web" 45 | if (!useIDENode && process.argv.length > 5 && process.argv[4] == "--config") { 46 | platform = process.argv[5].replace(".json", ""); 47 | } 48 | if (useIDENode && process.argv.length >= 4 && process.argv[3].startsWith("--config") && process.argv[3].endsWith(".json")) { 49 | platform = process.argv[3].match(/(\w+).json/)[1]; 50 | } 51 | let _path; 52 | if (!useIDENode) { 53 | _path = platform + ".json"; 54 | releaseDir = "../release/" + platform; 55 | } 56 | if (useIDENode) { 57 | _path = path.join(workSpaceDir, ".laya", `${platform}.json`); 58 | releaseDir = path.join(workSpaceDir, "release", platform).replace(/\\/g, "/"); 59 | } 60 | global.platform = platform; 61 | let file = fs.readFileSync(_path, "utf-8"); 62 | if (file) { 63 | file = file.replace(/\$basePath/g, releaseDir); 64 | config = JSON.parse(file); 65 | global.config = config; 66 | } 67 | // 是否是开放域项目 68 | let projInfoPath = path.join(workSpaceDir, path.basename(workSpaceDir) + ".laya"); 69 | let isExist = fs.existsSync(projInfoPath); 70 | if (isExist) { 71 | try { 72 | let projInfo = fs.readFileSync(projInfoPath, "utf8"); 73 | projInfo = projInfo && JSON.parse(projInfo); 74 | isOpendataProj = projInfo.layaProType === 12; 75 | } catch (e) {} 76 | } 77 | }); 78 | 79 | // 重新编译项目 80 | // gulp.task("compile", ["loadConfig"], function () { 81 | // if (config.compile) { 82 | // console.log("compile"); 83 | // } 84 | // }); 85 | 86 | // 清理release文件夹 87 | gulp.task("clearReleaseDir", ["compile"], function (cb) { 88 | if (config.clearReleaseDir) { 89 | let delList = [releaseDir, releaseDir + "_pack", config.packfileTargetValue]; 90 | // 小米快游戏,使用即存的项目,删掉Laya工程文件,保留小米环境项目文件 91 | if (platform === "xmgame") { 92 | let xmProjSrc = path.join(releaseDir, config.xmInfo.projName); 93 | // 不要删掉manifest.json/main.js文件 94 | // 这里不是node-glob语法,详见: https://github.com/sindresorhus/del 95 | delList = [`${xmProjSrc}/**`, `!${xmProjSrc}`, `!${xmProjSrc}/node_modules/**`, `!${xmProjSrc}/sign/**`, `!${xmProjSrc}/{babel.config.js,main.js,manifest.json,package.json,package-lock.json}`]; 96 | } else if (platform === "oppogame") { 97 | let oppoProjSrc = path.join(releaseDir, config.oppoInfo.projName); 98 | delList = [`${oppoProjSrc}/**`, `!${oppoProjSrc}`, `!${oppoProjSrc}/dist/**`, `!${oppoProjSrc}/{manifest.json}`]; 99 | } 100 | del(delList, { force: true }).then(paths => { 101 | cb(); 102 | }); 103 | } else cb(); 104 | }); 105 | 106 | // copy bin文件到release文件夹 107 | gulp.task("copyFile", ["clearReleaseDir"], function () { 108 | let baseCopyFilter = [`${workSpaceDir}/bin/**/*.*`]; 109 | // 只拷贝index.js中引用的类库 110 | if (config.onlyIndexJS) { 111 | baseCopyFilter = baseCopyFilter.concat(`!${workSpaceDir}/bin/libs/*.*`); 112 | } 113 | if (platform === "wxgame" && isOpendataProj) { // 开放域项目微信发布,仅拷贝用到的文件 114 | config.copyFilesFilter = [`${workSpaceDir}/bin/js/bundle.js`, `${workSpaceDir}/bin/index.js`, `${workSpaceDir}/bin/game.js`]; 115 | if (config.projectType !== "as") { // 开放域精简类库 116 | config.copyFilesFilter.push(`${workSpaceDir}/bin/libs/laya.opendata.min.js`); 117 | } 118 | } else if (platform === "wxgame") { // 微信项目,不拷贝index.html,不拷贝百度bin目录中的文件 119 | config.copyFilesFilter = baseCopyFilter.concat([`!${workSpaceDir}/bin/index.html`, `!${workSpaceDir}/bin/{project.swan.json,swan-game-adapter.js}`]); 120 | } else if (platform === "bdgame") { // 百度项目,不拷贝index.html,不拷贝微信bin目录中的文件 121 | config.copyFilesFilter = baseCopyFilter.concat([`!${workSpaceDir}/bin/index.html`, `!${workSpaceDir}/bin/{project.config.json,weapp-adapter.js}`]); 122 | } else { // web|QQ项目|小米快游戏,不拷贝微信、百度在bin目录中的文件 123 | config.copyFilesFilter = baseCopyFilter.concat([`!${workSpaceDir}/bin/{game.js,game.json,project.config.json,weapp-adapter.js,project.swan.json,swan-game-adapter.js}`]); 124 | } 125 | // 小米快游戏,需要新建一个快游戏项目,拷贝的只是项目的一部分,将文件先拷贝到文件夹的临时目录中去 126 | let QUICKGAMELIST = ["xmgame", "oppogame"]; 127 | if (QUICKGAMELIST.includes(platform)) { 128 | releaseDir = global.tempReleaseDir = path.join(releaseDir, "temprelease"); 129 | } 130 | global.releaseDir = releaseDir; 131 | var stream = gulp.src(config.copyFilesFilter, { base: `${workSpaceDir}/bin` }); 132 | return stream.pipe(gulp.dest(releaseDir)); 133 | }); 134 | 135 | // copy libs中的js文件到release文件夹 136 | gulp.task("copyLibsJsFile", ["copyFile"], function () { 137 | if (!config.onlyIndexJS) { 138 | return; 139 | } 140 | if (platform === "wxgame" && isOpendataProj) { // 开放域项目微信发布,拷贝文件时已经拷贝类库文件了 141 | return; 142 | } 143 | // 开放域项目,as语言,没有libs目录,mac系统报错 144 | let libs = path.join(workSpaceDir, "bin", "libs"); 145 | if (!fs.existsSync(libs)) { 146 | return; 147 | } 148 | // 分析index.js 149 | let indexJSPath = path.join(workSpaceDir, "bin", "index.js"); 150 | let indexJsContent = fs.readFileSync(indexJSPath, "utf8"); 151 | let libsList = indexJsContent.match(/loadLib\(['"]libs\/[a-zA-z0-9\/\.]+\.(js|wasm)['"]\)/g); 152 | if (!libsList) { 153 | libsList = []; 154 | } 155 | let 156 | item, 157 | libsName = "", 158 | libsStr = ""; 159 | for (let i = 0, len = libsList.length; i < len; i++) { 160 | item = libsList[i]; 161 | libsName = item.match(/loadLib\(['"]libs\/([a-zA-z0-9\/\.]+\.(js|wasm))['"]\)/); 162 | libsStr += libsStr ? `,${libsName[1]}` : libsName[1]; 163 | } 164 | let copyLibsList = [`${workSpaceDir}/bin/libs/{${libsStr}}`]; 165 | if (!libsStr.includes(",")) { 166 | copyLibsList = [`${workSpaceDir}/bin/libs/${libsStr}`]; 167 | } 168 | // 微信、百度,需要拷贝对应平台的类库 169 | if (platform === "wxgame") { 170 | copyLibsList.push(`${workSpaceDir}/bin/libs/laya.wxmini.js`); 171 | } else if (platform === "bdgame") { 172 | copyLibsList.push(`${workSpaceDir}/bin/libs/laya.bdmini.js`); 173 | } 174 | var stream = gulp.src(copyLibsList, { base: `${workSpaceDir}/bin` }); 175 | return stream.pipe(gulp.dest(releaseDir)); 176 | }); 177 | 178 | // 根据不同的项目类型拷贝平台文件 179 | gulp.task("copyPlatformFile", ["copyLibsJsFile"], function () { 180 | let fileLibsPath; 181 | if (useIDENode) { 182 | fileLibsPath = path.join(ideModuleDir, "../", "out", "layarepublic", "LayaAirProjectPack", "lib", "data"); 183 | } else if (process.argv.length >= 8 && process.argv[6] === "--libspath") { 184 | fileLibsPath = process.argv[7]; 185 | console.log("平台文件包是否存在: " + fs.existsSync(fileLibsPath)); 186 | } else { 187 | console.log("没有接收到可用文件包位置,不拷贝对应平台文件"); 188 | return; 189 | } 190 | // 开放域项目,微信发布 191 | if (platform === "wxgame" && isOpendataProj) { 192 | let platformDir = path.join(fileLibsPath, "wxfiles", "weapp-adapter.js"); 193 | let stream = gulp.src(platformDir); 194 | return stream.pipe(gulp.dest(releaseDir)); 195 | } 196 | // 微信项目,非开放域项目 197 | if (platform === "wxgame") { 198 | // 如果新建项目时已经点击了"微信/百度小游戏bin目录快速调试",不再拷贝 199 | let isHadWXFiles = 200 | fs.existsSync(path.join(workSpaceDir, "bin", "game.js")) && 201 | fs.existsSync(path.join(workSpaceDir, "bin", "game.json")) && 202 | fs.existsSync(path.join(workSpaceDir, "bin", "project.config.json")) && 203 | fs.existsSync(path.join(workSpaceDir, "bin", "weapp-adapter.js")); 204 | if (isHadWXFiles) { 205 | return; 206 | } 207 | let platformDir = path.join(fileLibsPath, "wxfiles"); 208 | let stream = gulp.src(platformDir + "/*.*"); 209 | return stream.pipe(gulp.dest(releaseDir)); 210 | } 211 | // qq玩一玩项目,区分语言 212 | if (platform === "qqwanyiwan") { 213 | let projectLangDir = config.projectType; 214 | let platformDir = path.join(fileLibsPath, "qqfiles", projectLangDir); 215 | let stream = gulp.src(platformDir + "/**/*.*"); 216 | return stream.pipe(gulp.dest(releaseDir)); 217 | } 218 | // 百度项目 219 | if (platform === "bdgame") { 220 | // 如果新建项目时已经点击了"微信/百度小游戏bin目录快速调试",不再拷贝 221 | let isHadBdFiles = 222 | fs.existsSync(path.join(workSpaceDir, "bin", "game.js")) && 223 | fs.existsSync(path.join(workSpaceDir, "bin", "game.json")) && 224 | fs.existsSync(path.join(workSpaceDir, "bin", "project.swan.json")) && 225 | fs.existsSync(path.join(workSpaceDir, "bin", "swan-game-adapter.js")); 226 | if (isHadBdFiles) { 227 | return; 228 | } 229 | let platformDir = path.join(fileLibsPath, "bdfiles"); 230 | let stream = gulp.src(platformDir + "/*.*"); 231 | return stream.pipe(gulp.dest(releaseDir)); 232 | } 233 | }); 234 | 235 | // 拷贝文件后,针对特定平台修改文件内容 236 | gulp.task("modifyFile", ["copyPlatformFile"], function () { 237 | // QQ玩一玩 238 | if (platform === "qqwanyiwan") { 239 | // 修改bundle.js 240 | let bundleFilePath = path.join(releaseDir, "js", "bundle.js"); 241 | if (fs.existsSync(bundleFilePath)) { 242 | let fileContent = fs.readFileSync(bundleFilePath, "utf8"); 243 | var appendCode = 'if(window["BK"]&&window["BK"]["Sprite"]){BK.Script.loadlib("GameRes://layaforqq/laya.bkadpter.js");}'; 244 | if (fileContent.includes("/**LayaGameStart**/") && !fileContent.includes(appendCode)) { 245 | fileContent = fileContent.split("/**LayaGameStart**/").join(`/**LayaGameStart**/\n${appendCode}`); 246 | fs.writeFileSync(bundleFilePath, fileContent, "utf8"); 247 | } 248 | } 249 | 250 | // 修改index.js 251 | let indexFilePath = path.join(releaseDir, "index.js"); 252 | if (fs.existsSync(indexFilePath)) { 253 | let fileContent = fs.readFileSync(indexFilePath, "utf8"); 254 | fileContent = fileContent.replace(/loadLib\("/g, "BK.Script.loadlib(\"GameRes://"); 255 | // 非as语言,要添加类库 256 | if ("as" !== config.projectType) { 257 | if (fileContent.includes("//-----libs-end-------")) { 258 | fileContent = fileContent.split("//-----libs-end-------").join(`//-----libs-end-------\nBK.Script.loadlib("GameRes://layaforqq/laya.bkadpter.js");`); 259 | } 260 | } 261 | fs.writeFileSync(indexFilePath, fileContent, "utf8"); 262 | } 263 | 264 | // 修改main.js 265 | let mainFilePath = path.join(releaseDir, "main.js"); 266 | if (fs.existsSync(mainFilePath)) { 267 | let fileContent = fs.readFileSync(mainFilePath, "utf8"); 268 | fileContent = `BK.Script.loadlib("GameRes://layaforqq/qqPlayCore.js"); 269 | BK.Script.loadlib("GameRes://layaforqq/bkadptpre.js"); 270 | BK.Script.loadlib("GameRes://layaforqq/domparserinone.js"); 271 | BK.Script.loadlib("GameRes://index.js");`; 272 | fs.writeFileSync(mainFilePath, fileContent, "utf8"); 273 | } 274 | 275 | return; 276 | } 277 | 278 | // 百度项目,修改index.js 279 | if (platform === "bdgame") { 280 | let filePath = path.join(releaseDir, "index.js"); 281 | if (!fs.existsSync(filePath)) { 282 | return; 283 | } 284 | let fileContent = fs.readFileSync(filePath, "utf8"); 285 | fileContent = fileContent.replace(/loadLib\(/g, "require("); 286 | fs.writeFileSync(filePath, fileContent, "utf8"); 287 | return; 288 | } 289 | }); 290 | 291 | // 压缩json 292 | gulp.task("compressJson", ["modifyFile"], function () { 293 | if (config.compressJson) { 294 | return gulp.src(config.compressJsonFilter, { base: releaseDir }) 295 | .pipe(jsonminify()) 296 | .pipe(gulp.dest(releaseDir)); 297 | } 298 | }); 299 | 300 | // 压缩js 301 | gulp.task("compressJs", ["compressJson"], function () { 302 | if (config.compressJs) { 303 | return gulp.src(config.compressJsFilter, { base: releaseDir }) 304 | .pipe(uglify()) 305 | .on('error', function (err) { 306 | console.warn(err.toString()); 307 | }) 308 | .pipe(gulp.dest(releaseDir)); 309 | } 310 | }); 311 | 312 | // 压缩png,jpg 313 | gulp.task("compressImage", ["compressJs"], function () { 314 | if (config.compressImage) { 315 | return gulp.src(config.compressImageFilter, { base: releaseDir }) 316 | .pipe(image({ 317 | pngquant: true, //PNG优化工具 318 | optipng: false, //PNG优化工具 319 | zopflipng: true, //PNG优化工具 320 | jpegRecompress: false, //jpg优化工具 321 | mozjpeg: true, //jpg优化工具 322 | guetzli: false, //jpg优化工具 323 | gifsicle: false, //gif优化工具 324 | svgo: false, //SVG优化工具 325 | concurrent: 10, //并发线程数 326 | quiet: true //是否是静默方式 327 | // optipng: ['-i 1', '-strip all', '-fix', '-o7', '-force'], 328 | // pngquant: ['--speed=1', '--force', 256], 329 | // zopflipng: ['-y', '--lossy_8bit', '--lossy_transparent'], 330 | // jpegRecompress: ['--strip', '--quality', 'medium', '--min', 40, '--max', 80], 331 | // mozjpeg: ['-optimize', '-progressive'], 332 | // guetzli: ['--quality', 85] 333 | })) 334 | .pipe(gulp.dest(releaseDir)); 335 | } 336 | }); 337 | 338 | // 开放域的情况下,合并game.js和index.js,并删除game.js 339 | gulp.task("openData", ["compressImage"], function (cb) { 340 | if (config.openDataZone) { 341 | let indexPath = releaseDir + "/index.js"; 342 | let indexjs = readFile(indexPath); 343 | let gamejs = readFile(releaseDir + "/game.js"); 344 | if (gamejs && indexjs) { 345 | gamejs = gamejs.replace('require("index.js")', indexjs); 346 | fs.writeFileSync(indexPath, gamejs, 'utf-8'); 347 | } 348 | if (isOpendataProj) { 349 | // 开放域项目,将game.js删掉,发布最小包 350 | del(`${releaseDir}/game.js`, { force: true }).then(paths => { 351 | cb(); 352 | }); 353 | } else { 354 | cb(); 355 | } 356 | } else { 357 | cb(); 358 | } 359 | }); 360 | 361 | function readFile(path) { 362 | if (fs.existsSync(path)) { 363 | return fs.readFileSync(path, "utf-8"); 364 | } 365 | return null; 366 | } 367 | 368 | // 生成版本管理信息 369 | gulp.task("version1", ["openData"], function () { 370 | if (config.version) { 371 | return gulp.src(config.versionFilter, { base: releaseDir }) 372 | .pipe(rev()) 373 | .pipe(gulp.dest(releaseDir)) 374 | .pipe(revdel()) 375 | .pipe(rev.manifest("version.json")) 376 | .pipe(gulp.dest(releaseDir)); 377 | } 378 | }); 379 | 380 | // 替换index.js里面的变化的文件名 381 | gulp.task("version2", ["version1"], function () { 382 | if (config.version) { 383 | //替换index.html和index.js里面的文件名称 384 | 385 | let htmlPath = releaseDir + "/index.html"; 386 | let versionPath = releaseDir + "/version.json"; 387 | let gameJSPath = releaseDir + "/game.js"; 388 | let mainJSPath = releaseDir + "/main.js"; 389 | let indexJSPath; 390 | let versionCon = fs.readFileSync(versionPath, "utf8"); 391 | versionCon = JSON.parse(versionCon); 392 | indexJSPath = releaseDir + "/" + versionCon["index.js"]; 393 | // 替换config.packfileFullValue中的路径 394 | let packfileStr = JSON.stringify(config.packfileFullValue).replace(/\\\\/g, "/"); 395 | let tempPackfile = `${workSpaceDir}/.laya/configTemp.json`; 396 | fs.writeFileSync(tempPackfile, packfileStr, "utf8"); 397 | 398 | let srcList = [versionPath, indexJSPath, tempPackfile]; 399 | if (fs.existsSync(htmlPath)) { 400 | srcList.push(htmlPath); 401 | } 402 | if (fs.existsSync(gameJSPath)) { 403 | srcList.push(gameJSPath); 404 | } 405 | if (fs.existsSync(mainJSPath)) { 406 | srcList.push(mainJSPath); 407 | } 408 | return gulp.src(srcList) 409 | .pipe(revCollector()) 410 | .pipe(gulp.dest(releaseDir)); 411 | } 412 | }); 413 | 414 | // 筛选4M包 415 | gulp.task("packfile", ["version2"], function() { 416 | if (config.version) { 417 | // 从release目录取得带有版本号的目录 418 | let tempPackfile = `${workSpaceDir}/.laya/configTemp.json`; 419 | let releasePackfile = `${releaseDir}/configTemp.json`; 420 | let packfileStr = fs.readFileSync(releasePackfile, "utf8"); 421 | config.packfileFullValue = JSON.parse(packfileStr); 422 | // 删掉临时目录 423 | fs.unlinkSync(tempPackfile); 424 | fs.unlinkSync(releasePackfile); 425 | } 426 | if (config.packfile) { // 提取本地包(文件列表形式) 427 | return gulp.src(config.packfileFullValue, { base: releaseDir }) 428 | .pipe(gulp.dest(config.packfileTargetValue || releaseDir + "_pack")); 429 | } 430 | }); 431 | 432 | // 起始任务 433 | gulp.task("publish", ["buildXiaomiProj", "buildOPPOProj"], function () { 434 | console.log("All tasks completed!"); 435 | }); -------------------------------------------------------------------------------- /.laya/publish_oppogame.js: -------------------------------------------------------------------------------- 1 | // v1.0.1 2 | // publish 2.x 也是用这个文件,需要做兼容 3 | let isPublish2 = process.argv[2].includes("publish_oppogame.js") && process.argv[3].includes("--evn=publish2"); 4 | // 获取Node插件和工作路径 5 | let ideModuleDir, workSpaceDir; 6 | if (isPublish2) { 7 | //是否使用IDE自带的node环境和插件,设置false后,则使用自己环境(使用命令行方式执行) 8 | const useIDENode = process.argv[0].indexOf("LayaAir") > -1 ? true : false; 9 | ideModuleDir = useIDENode ? process.argv[1].replace("gulp\\bin\\gulp.js", "").replace("gulp/bin/gulp.js", "") : ""; 10 | workSpaceDir = useIDENode ? process.argv[2].replace("--gulpfile=", "").replace("\\.laya\\publish_oppogame.js", "").replace("/.laya/publish_oppogame.js", "") + "/" : "./../"; 11 | } else { 12 | ideModuleDir = global.ideModuleDir; 13 | workSpaceDir = global.workSpaceDir; 14 | } 15 | 16 | //引用插件模块 17 | const gulp = require(ideModuleDir + "gulp"); 18 | const fs = require("fs"); 19 | const path = require("path"); 20 | const childProcess = require("child_process"); 21 | const del = require(ideModuleDir + "del"); 22 | let commandSuffix = ".cmd"; 23 | 24 | let prevTasks = ["packfile"]; 25 | if (isPublish2) { 26 | prevTasks = ""; 27 | } 28 | 29 | let 30 | config, 31 | platform, 32 | releaseDir, 33 | toolkitPath, 34 | tempReleaseDir, // OPPO临时拷贝目录 35 | projDir; // OPPO快游戏工程目录 36 | // 创建OPPO项目前,拷贝OPPO引擎库、修改index.js 37 | // 应该在publish中的,但是为了方便发布2.0及IDE 1.x,放在这里修改 38 | gulp.task("preCreate_OPPO", prevTasks, function() { 39 | if (isPublish2) { 40 | let pubsetPath = path.join(workSpaceDir, ".laya", "pubset.json"); 41 | let content = fs.readFileSync(pubsetPath, "utf8"); 42 | let pubsetJson = JSON.parse(content); 43 | platform = "oppogame"; 44 | releaseDir = path.join(workSpaceDir, "release", platform).replace(/\\/g, "/"); 45 | releaseDir = tempReleaseDir = path.join(releaseDir, "temprelease"); 46 | config = pubsetJson[5]; // 只用到了 config.oppoInfo|config.oppoSign 47 | } else { 48 | platform = global.platform; 49 | releaseDir = global.releaseDir; 50 | tempReleaseDir = global.tempReleaseDir; 51 | config = global.config; 52 | } 53 | toolkitPath = path.join(ideModuleDir, "../", "out", "layarepublic", "oppo", "quickgame-toolkit"); 54 | // 如果不是OPPO快游戏 55 | if (platform !== "oppogame") { 56 | return; 57 | } 58 | if (process.platform === "darwin") { 59 | commandSuffix = ""; 60 | } 61 | let copyLibsList = [`${workSpaceDir}/bin/libs/laya.quickgamemini.js`]; 62 | var stream = gulp.src(copyLibsList, { base: `${workSpaceDir}/bin` }); 63 | return stream.pipe(gulp.dest(tempReleaseDir)); 64 | }); 65 | 66 | // 新建OPPO项目-OPPO项目与其他项目不同,需要安装OPPO quickgame node_modules,并打包成.rpk文件 67 | gulp.task("installModules_OPPO", ["preCreate_OPPO"], function() { 68 | // 如果不是OPPO快游戏 69 | if (platform !== "oppogame") { 70 | return; 71 | } 72 | releaseDir = path.dirname(releaseDir); 73 | projDir = path.join(releaseDir, config.oppoInfo.projName); 74 | // 如果IDE里对应OPPO包已经install node_modules了,忽略这一步 75 | if (fs.existsSync(path.join(toolkitPath, "node_modules"))) { 76 | return; 77 | } 78 | // 安装OPPO quickgame node_modules 79 | return new Promise((resolve, reject) => { 80 | console.log("开始安装OPPO quickgame node_modules,请耐心等待..."); 81 | let cmd = `npm${commandSuffix}`; 82 | let args = ["install"]; 83 | 84 | let cp = childProcess.spawn(cmd, args, { 85 | cwd: toolkitPath 86 | }); 87 | 88 | cp.stdout.on('data', (data) => { 89 | console.log(`stdout: ${data}`); 90 | }); 91 | 92 | cp.stderr.on('data', (data) => { 93 | console.log(`stderr: ${data}`); 94 | // reject(); 95 | }); 96 | 97 | cp.on('close', (code) => { 98 | console.log(`子进程退出码:${code}`); 99 | resolve(); 100 | }); 101 | }); 102 | }); 103 | 104 | // 拷贝文件到OPPO快游戏 105 | gulp.task("copyFileToProj_OPPO", ["installModules_OPPO"], function() { 106 | // 如果不是OPPO快游戏 107 | if (platform !== "oppogame") { 108 | return; 109 | } 110 | // 将临时文件夹中的文件,拷贝到项目中去 111 | let originalDir = `${tempReleaseDir}/**/*.*`; 112 | let stream = gulp.src(originalDir); 113 | return stream.pipe(gulp.dest(path.join(projDir))); 114 | }); 115 | 116 | // 拷贝icon到OPPO快游戏 117 | gulp.task("copyIconToProj_OPPO", ["copyFileToProj_OPPO"], function() { 118 | // 如果不是OPPO快游戏 119 | if (platform !== "oppogame") { 120 | return; 121 | } 122 | let originalDir = config.oppoInfo.icon; 123 | let stream = gulp.src(originalDir); 124 | return stream.pipe(gulp.dest(path.join(projDir))); 125 | }); 126 | 127 | // 清除OPPO快游戏临时目录 128 | gulp.task("clearTempDir_OPPO", ["copyIconToProj_OPPO"], function() { 129 | // 如果不是OPPO快游戏 130 | if (platform !== "oppogame") { 131 | return; 132 | } 133 | // 删掉临时目录 134 | return del([tempReleaseDir], { force: true }); 135 | }); 136 | 137 | // 生成release签名(私钥文件 private.pem 和证书文件 certificate.pem ) 138 | gulp.task("generateSign_OPPO", ["clearTempDir_OPPO"], function() { 139 | // 如果不是OPPO快游戏 140 | if (platform !== "oppogame") { 141 | return; 142 | } 143 | if (!config.oppoSign.generateSign) { 144 | return; 145 | } 146 | // https://doc.quickapp.cn/tools/compiling-tools.html 147 | return new Promise((resolve, reject) => { 148 | let cmd = "openssl"; 149 | let args = ["req", "-newkey", "rsa:2048", "-nodes", "-keyout", "private.pem", 150 | "-x509", "-days", "3650", "-out", "certificate.pem"]; 151 | let opts = { 152 | cwd: projDir, 153 | shell: true 154 | }; 155 | let cp = childProcess.spawn(cmd, args, opts); 156 | cp.stdout.on('data', (data) => { 157 | console.log(`stdout: ${data}`); 158 | }); 159 | 160 | cp.stderr.on('data', (data) => { 161 | console.log(`stderr: ${data}`); 162 | data += ""; 163 | if (data.includes("Country Name")) { 164 | cp.stdin.write(`${config.oppoSign.countryName}\n`); 165 | console.log(`Country Name: ${config.oppoSign.countryName}`); 166 | } else if (data.includes("Province Name")) { 167 | cp.stdin.write(`${config.oppoSign.provinceName}\n`); 168 | console.log(`Province Name: ${config.oppoSign.provinceName}`); 169 | } else if (data.includes("Locality Name")) { 170 | cp.stdin.write(`${config.oppoSign.localityName}\n`); 171 | console.log(`Locality Name: ${config.oppoSign.localityName}`); 172 | } else if (data.includes("Organization Name")) { 173 | cp.stdin.write(`${config.oppoSign.orgName}\n`); 174 | console.log(`Organization Name: ${config.oppoSign.orgName}`); 175 | } else if (data.includes("Organizational Unit Name")) { 176 | cp.stdin.write(`${config.oppoSign.orgUnitName}\n`); 177 | console.log(`Organizational Unit Name: ${config.oppoSign.orgUnitName}`); 178 | } else if (data.includes("Common Name")) { 179 | cp.stdin.write(`${config.oppoSign.commonName}\n`); 180 | console.log(`Common Name: ${config.oppoSign.commonName}`); 181 | } else if (data.includes("Email Address")) { 182 | cp.stdin.write(`${config.oppoSign.emailAddr}\n`); 183 | console.log(`Email Address: ${config.oppoSign.emailAddr}`); 184 | // cp.stdin.end(); 185 | } 186 | // reject(); 187 | }); 188 | 189 | cp.on('close', (code) => { 190 | console.log(`子进程退出码:${code}`); 191 | resolve(); 192 | }); 193 | }); 194 | }); 195 | 196 | // 拷贝sign文件到指定位置 197 | gulp.task("copySignFile_OPPO", ["generateSign_OPPO"], function() { 198 | // 如果不是OPPO快游戏 199 | if (platform !== "oppogame") { 200 | return; 201 | } 202 | if (config.oppoSign.generateSign) { // 新生成的签名 203 | // 移动签名文件到项目中(Laya & OPPO快游戏项目中) 204 | let 205 | privatePem = path.join(projDir, "private.pem"), 206 | certificatePem = path.join(projDir, "certificate.pem"); 207 | let isSignExits = fs.existsSync(privatePem) && fs.existsSync(certificatePem); 208 | if (!isSignExits) { 209 | return; 210 | } 211 | let 212 | xiaomiDest = `${projDir}/sign/release`, 213 | layaDest = `${workSpaceDir}/sign/release`; 214 | let stream = gulp.src([privatePem, certificatePem]); 215 | return stream.pipe(gulp.dest(xiaomiDest)) 216 | .pipe(gulp.dest(layaDest)); 217 | } else if (config.oppoInfo.useReleaseSign && !config.oppoSign.generateSign) { // 使用release签名,并且没有重新生成 218 | // 从项目中将签名拷贝到OPPO快游戏项目中 219 | let 220 | privatePem = path.join(workSpaceDir, "sign", "release", "private.pem"), 221 | certificatePem = path.join(workSpaceDir, "sign", "release", "certificate.pem"); 222 | let isSignExits = fs.existsSync(privatePem) && fs.existsSync(certificatePem); 223 | if (!isSignExits) { 224 | return; 225 | } 226 | let 227 | xiaomiDest = `${projDir}/sign/release`; 228 | let stream = gulp.src([privatePem, certificatePem]); 229 | return stream.pipe(gulp.dest(xiaomiDest)); 230 | } 231 | }); 232 | 233 | gulp.task("deleteSignFile_OPPO", ["copySignFile_OPPO"], function() { 234 | // 如果不是OPPO快游戏 235 | if (platform !== "oppogame") { 236 | return; 237 | } 238 | if (config.oppoSign.generateSign) { // 新生成的签名 239 | let 240 | privatePem = path.join(projDir, "private.pem"), 241 | certificatePem = path.join(projDir, "certificate.pem"); 242 | return del([privatePem, certificatePem], { force: true }); 243 | } 244 | }); 245 | 246 | gulp.task("modifyFile_OPPO", ["deleteSignFile_OPPO"], function() { 247 | // 如果不是OPPO快游戏 248 | if (platform !== "oppogame") { 249 | return; 250 | } 251 | // 修改manifest.json文件 252 | let manifestPath = path.join(projDir, "manifest.json"); 253 | let IDEManifestPath = path.join(toolkitPath, "tpl", "manifest.json"); 254 | if (!fs.existsSync(IDEManifestPath)) { 255 | return; 256 | } 257 | let manifestContent = fs.readFileSync(IDEManifestPath, "utf8"); 258 | let manifestJson = JSON.parse(manifestContent); 259 | manifestJson.package = config.oppoInfo.package; 260 | manifestJson.name = config.oppoInfo.name; 261 | manifestJson.orientation = config.oppoInfo.orientation; 262 | manifestJson.versionName = config.oppoInfo.versionName; 263 | manifestJson.versionCode = config.oppoInfo.versionCode; 264 | manifestJson.minPlatformVersion = config.oppoInfo.minPlatformVersion; 265 | manifestJson.icon = `./${path.basename(config.oppoInfo.icon)}`; 266 | if (config.oppoInfo.subpack) { 267 | manifestJson.subpackages = config.oppoSubpack; 268 | } 269 | fs.writeFileSync(manifestPath, JSON.stringify(manifestJson, null, 4), "utf8"); 270 | 271 | // OPPO项目,修改main.js 272 | let filePath = path.join(projDir, "main.js"); 273 | // 这个地方,1.x IDE和2.x IDE 不一致 274 | let fileContent = `window.navigator.userAgent = 'Mozilla/5.0 (Linux; Android 5.1.1; Nexus 6 Build/LYZ28E) AppleWebKit/603.1.30 (KHTML, like Gecko) Mobile/14E8301 OPPO MiniGame NetType/WIFI Language/zh_CN'; 275 | require("./libs/laya.quickgamemini.js");\nrequire("index.js");`; 276 | fs.writeFileSync(filePath, fileContent, "utf8"); 277 | 278 | // OPPO项目,修改index.js 279 | let indexFilePath = path.join(projDir, "index.js"); 280 | if (!fs.existsSync(indexFilePath)) { 281 | return; 282 | } 283 | let indexFileContent = fs.readFileSync(indexFilePath, "utf8"); 284 | indexFileContent = indexFileContent.replace(/loadLib(\(['"])/gm, "require$1./"); 285 | fs.writeFileSync(indexFilePath, indexFileContent, "utf8"); 286 | }); 287 | 288 | // 打包rpk 289 | gulp.task("buildRPK_OPPO", ["modifyFile_OPPO"], function() { 290 | // 如果不是OPPO快游戏 291 | if (platform !== "oppogame") { 292 | return; 293 | } 294 | // 在OPPO轻游戏项目目录中执行: 295 | // quickgame pack || quickgame pack release 296 | // quickgame subpack --no-build-js || quickgame subpack release --no-build-js 297 | let cmdStr = ""; 298 | let packStr = "pack"; 299 | let nobuildjs = ""; 300 | if (config.oppoInfo.subpack) { 301 | packStr = "subpack"; 302 | nobuildjs = "--no-build-js"; 303 | } 304 | if (config.oppoInfo.useReleaseSign) { 305 | cmdStr = "release"; 306 | } 307 | return new Promise((resolve, reject) => { 308 | let cmd = path.join(toolkitPath, "lib", "bin", `quickgame${commandSuffix}`); 309 | let args = [packStr, cmdStr, nobuildjs]; 310 | let opts = { 311 | cwd: projDir 312 | }; 313 | let cp = childProcess.spawn(cmd, args, opts); 314 | // let cp = childProcess.spawn('npx.cmd', ['-v']); 315 | cp.stdout.on('data', (data) => { 316 | console.log(`stdout: ${data}`); 317 | }); 318 | 319 | cp.stderr.on('data', (data) => { 320 | console.log(`stderr: ${data}`); 321 | // reject(); 322 | }); 323 | 324 | cp.on('close', (code) => { 325 | console.log(`子进程退出码:${code}`); 326 | resolve(); 327 | }); 328 | }); 329 | }); 330 | 331 | gulp.task("pushRPK_OPPO", ["buildRPK_OPPO"], function() { 332 | // 如果不是OPPO快游戏 333 | if (platform !== "oppogame") { 334 | return; 335 | } 336 | if (!config.oppoInfo.oppoDebug) { 337 | return; 338 | } 339 | // 在OPPO轻游戏项目目录中执行: 340 | // adb push dist/game.rpk sdcard/games 341 | // adb push idePath/resources/app/out/layarepublic/oppo/instant_app_settings.properties 342 | // adb shell am start -n com.nearme.instant.platform/com.oppo.autotest.main.InstantAppActivity 343 | return new Promise((resolve, reject) => { 344 | let cmd = "adb"; 345 | let sdGamesPath = config.oppoInfo.subpack ? "sdcard/subPkg" : "sdcard/games"; 346 | let args = ["push", `dist/${config.oppoInfo.package}${config.oppoInfo.useReleaseSign ? ".signed" : ""}.rpk`, sdGamesPath]; 347 | let opts = { 348 | cwd: projDir 349 | }; 350 | let cp = childProcess.spawn(cmd, args, opts); 351 | // let cp = childProcess.spawn('npx.cmd', ['-v']); 352 | cp.stdout.on('data', (data) => { 353 | console.log(`stdout: ${data}`); 354 | }); 355 | 356 | cp.stderr.on('data', (data) => { 357 | console.log(`stderr: ${data}`); 358 | // reject(); 359 | }); 360 | 361 | cp.on('close', (code) => { 362 | console.log(`1) push_RPK 子进程退出码:${code}`); 363 | resolve(); 364 | }); 365 | }).then(() => { 366 | return new Promise((resolve, reject) => { 367 | // 如果是分包,需要修改里面的内容 368 | let oppoPropPath = path.join(ideModuleDir, "../", `/out/layarepublic/oppo/instant_app_settings.properties`); 369 | if (config.oppoInfo.subpack) { 370 | fs.writeFileSync(oppoPropPath, "default_tab_index=4", "utf8"); 371 | } else { 372 | fs.writeFileSync(oppoPropPath, "default_tab_index=2", "utf8"); 373 | } 374 | let cmd = "adb"; 375 | let args = ["push", oppoPropPath, "sdcard/"]; 376 | let opts = { 377 | cwd: projDir 378 | }; 379 | let cp = childProcess.spawn(cmd, args, opts); 380 | // let cp = childProcess.spawn('npx.cmd', ['-v']); 381 | cp.stdout.on('data', (data) => { 382 | console.log(`stdout: ${data}`); 383 | }); 384 | 385 | cp.stderr.on('data', (data) => { 386 | console.log(`stderr: ${data}`); 387 | // reject(); 388 | }); 389 | 390 | cp.on('close', (code) => { 391 | console.log(`2) push_RPK 子进程退出码:${code}`); 392 | resolve(); 393 | }); 394 | }); 395 | }).then(() => { 396 | return new Promise((resolve, reject) => { 397 | let cmd = "adb"; 398 | let args = ["shell", "am", "start", "-n", "com.nearme.instant.platform/com.oppo.autotest.main.InstantAppActivity"]; 399 | let opts = { 400 | cwd: projDir 401 | }; 402 | let cp = childProcess.spawn(cmd, args, opts); 403 | // let cp = childProcess.spawn('npx.cmd', ['-v']); 404 | cp.stdout.on('data', (data) => { 405 | console.log(`stdout: ${data}`); 406 | }); 407 | 408 | cp.stderr.on('data', (data) => { 409 | console.log(`stderr: ${data}`); 410 | // reject(); 411 | }); 412 | 413 | cp.on('close', (code) => { 414 | console.log(`3) push_RPK 子进程退出码:${code}`); 415 | resolve(); 416 | }); 417 | }); 418 | }); 419 | }); 420 | 421 | gulp.task("buildOPPOProj", ["pushRPK_OPPO"], function() { 422 | console.log("all tasks completed"); 423 | }); -------------------------------------------------------------------------------- /.laya/publish_xmgame.js: -------------------------------------------------------------------------------- 1 | // v1.1.0 2 | // publish 2.x 也是用这个文件,需要做兼容 3 | let isPublish2 = process.argv[2].includes("publish_xmgame.js") && process.argv[3].includes("--evn=publish2"); 4 | // 获取Node插件和工作路径 5 | let ideModuleDir, workSpaceDir; 6 | if (isPublish2) { 7 | //是否使用IDE自带的node环境和插件,设置false后,则使用自己环境(使用命令行方式执行) 8 | const useIDENode = process.argv[0].indexOf("LayaAir") > -1 ? true : false; 9 | ideModuleDir = useIDENode ? process.argv[1].replace("gulp\\bin\\gulp.js", "").replace("gulp/bin/gulp.js", "") : ""; 10 | workSpaceDir = useIDENode ? process.argv[2].replace("--gulpfile=", "").replace("\\.laya\\publish_xmgame.js", "").replace("/.laya/publish_xmgame.js", "") + "/" : "./../"; 11 | } else { 12 | ideModuleDir = global.ideModuleDir; 13 | workSpaceDir = global.workSpaceDir; 14 | } 15 | 16 | //引用插件模块 17 | const gulp = require(ideModuleDir + "gulp"); 18 | const fs = require("fs"); 19 | const path = require("path"); 20 | const childProcess = require("child_process"); 21 | const del = require(ideModuleDir + "del"); 22 | let commandSuffix = ".cmd"; 23 | 24 | let prevTasks = ["packfile"]; 25 | if (isPublish2) { 26 | prevTasks = ""; 27 | } 28 | 29 | let 30 | config, 31 | platform, 32 | releaseDir, 33 | tempReleaseDir, // 小米临时拷贝目录 34 | projDir; // 小米快游戏工程目录 35 | let IDEXMProjPath, 36 | isUpdateIDEXMProj = false; 37 | // 创建小米项目前,拷贝小米引擎库、修改index.js 38 | // 应该在publish中的,但是为了方便发布2.0及IDE 1.x,放在这里修改 39 | gulp.task("preCreate_XM", prevTasks, function() { 40 | if (isPublish2) { 41 | let pubsetPath = path.join(workSpaceDir, ".laya", "pubset.json"); 42 | let content = fs.readFileSync(pubsetPath, "utf8"); 43 | let pubsetJson = JSON.parse(content); 44 | platform = "xmgame"; 45 | releaseDir = path.join(workSpaceDir, "release", platform).replace(/\\/g, "/"); 46 | releaseDir = tempReleaseDir = path.join(releaseDir, "temprelease"); 47 | config = pubsetJson[4]; // 只用到了 config.xmInfo|config.xmSign 48 | } else { 49 | platform = global.platform; 50 | releaseDir = global.releaseDir; 51 | tempReleaseDir = global.tempReleaseDir; 52 | config = global.config; 53 | } 54 | // 如果不是小米快游戏 55 | if (platform !== "xmgame") { 56 | return; 57 | } 58 | if (process.platform === "darwin") { 59 | commandSuffix = ""; 60 | } 61 | let copyLibsList = [`${workSpaceDir}/bin/libs/laya.xmmini.js`]; 62 | var stream = gulp.src(copyLibsList, { base: `${workSpaceDir}/bin` }); 63 | return stream.pipe(gulp.dest(tempReleaseDir)); 64 | }); 65 | 66 | gulp.task("copyPlatformFile_XM", ["preCreate_XM"], function() { 67 | // 如果不是小米快游戏 68 | if (platform !== "xmgame") { 69 | return; 70 | } 71 | let xmAdapterPath = path.join(ideModuleDir, "../", "out", "layarepublic", "LayaAirProjectPack", "lib", "data", "xmfiles"); 72 | let copyLibsList = [`${xmAdapterPath}/**/*.*`]; 73 | var stream = gulp.src(copyLibsList); 74 | return stream.pipe(gulp.dest(tempReleaseDir)); 75 | }); 76 | 77 | // 新建小米项目-小米项目与其他项目不同,需要新建小米快游戏项目,并打包成.rpk文件 78 | gulp.task("checkIDEProj_XM", ["copyPlatformFile_XM"], function() { 79 | // 如果不是小米快游戏 80 | if (platform !== "xmgame") { 81 | return; 82 | } 83 | if (!ideModuleDir) { 84 | return; 85 | } 86 | IDEXMProjPath = path.join(ideModuleDir, "../", "out", "layarepublic", "xm"); 87 | if (process.platform === "darwin") { 88 | return; 89 | } 90 | let ideLastXMProjPath = path.join(IDEXMProjPath, config.xmInfo.projName); 91 | // 如果IDE中没有小米项目,跳过这一步 92 | let isProjExist = fs.existsSync(ideLastXMProjPath + "/node_modules") && 93 | fs.existsSync(ideLastXMProjPath + "/sign"); 94 | if (!isProjExist) { 95 | console.log("IDE中没有小米项目,跳过检查小米项目版本号这一步"); 96 | return; 97 | } 98 | // 如果IDE中项目已经存在了,检查版本号 99 | // npm view quickgame-cli version 100 | // npm ls quickgame-cli 101 | let remoteVersion, localVersion; 102 | let isGetRemote, isGetLocal; 103 | return new Promise((resolve, reject) => { // 远程版本号 104 | childProcess.exec("npm view quickgame-cli version", function(error, stdout, stderr) { 105 | if (!stdout) { // 获取 quickgame-cli 远程版本号失败 106 | reject(); 107 | return; 108 | } 109 | remoteVersion = stdout; 110 | isGetRemote = true; 111 | if (isGetRemote && isGetLocal) { 112 | resolve(); 113 | } 114 | }); 115 | childProcess.exec("npm ls quickgame-cli", { cwd: ideLastXMProjPath }, function(error, stdout, stderr) { 116 | if (!stdout) { // 获取 quickgame-cli 本地版本号失败 117 | reject(); 118 | return; 119 | } 120 | localVersion = stdout.match(/quickgame-cli@(.+)/); 121 | localVersion = localVersion && localVersion[1]; 122 | isGetLocal = true; 123 | if (isGetRemote && isGetLocal) { 124 | resolve(); 125 | } 126 | }); 127 | setTimeout(() => { 128 | if (!isGetLocal || !isGetRemote) { 129 | console.log("获取远程版本号或本地版本号失败"); 130 | reject(); 131 | return; 132 | } 133 | }, 10000); 134 | }).then(() => { // 比较两个版本号 135 | if (!remoteVersion || !localVersion) { 136 | console.log("获取远程版本号或本地版本号失败!"); 137 | } 138 | console.log("quickgame-cli -> ", localVersion, "|", remoteVersion); 139 | if (remoteVersion.trim() !== localVersion.trim()) { // 仅当两个版本号都获取到并且不相等,置为需要更新(true) 140 | isUpdateIDEXMProj = true; 141 | } 142 | }).catch((e) => { 143 | console.log("获取远程版本号或本地版本号失败 -> ", remoteVersion, "|", localVersion); 144 | console.log(e); 145 | }); 146 | }); 147 | 148 | gulp.task("createIDEProj_XM", ["checkIDEProj_XM"], function() { 149 | // 如果不是小米快游戏 150 | if (platform !== "xmgame") { 151 | return; 152 | } 153 | if (!ideModuleDir) { 154 | return; 155 | } 156 | if (process.platform === "darwin") { 157 | return; 158 | } 159 | let ideLastXMProjPath = path.join(IDEXMProjPath, config.xmInfo.projName); 160 | // 如果有即存项目,不再新建 161 | let isProjExist = fs.existsSync(ideLastXMProjPath + "/node_modules") && 162 | fs.existsSync(ideLastXMProjPath + "/sign"); 163 | if (isProjExist && !isUpdateIDEXMProj) { // 项目存在并且不需要更新IDE中的小米项目 164 | return; 165 | } 166 | return new Promise((resolve, reject) => { 167 | console.log("(IDE)开始创建小米快游戏项目,请耐心等待(预计需要10分钟)..."); 168 | let cmd = `npx${commandSuffix}`; 169 | let args = ["create-quickgame", config.xmInfo.projName, `path=${IDEXMProjPath}`, 170 | `package=${config.xmInfo.package}`, `versionName=${config.xmInfo.versionName}`, 171 | `versionCode=${config.xmInfo.versionCode}`, `minPlatformVersion=${config.xmInfo.minPlatformVersion}`, 172 | `icon=/layaicon/${path.basename(config.xmInfo.icon)}`, `name=${config.xmInfo.name}`, `rebuild=true`]; 173 | console.log(JSON.stringify(args)); 174 | 175 | let cp = childProcess.spawn(cmd, args); 176 | 177 | cp.stdout.on('data', (data) => { 178 | console.log(`stdout: ${data}`); 179 | }); 180 | 181 | cp.stderr.on('data', (data) => { 182 | console.log(`stderr: ${data}`); 183 | // reject(); 184 | }); 185 | 186 | cp.on('close', (code) => { 187 | console.log(`子进程退出码:${code}`); 188 | resolve(); 189 | }); 190 | }); 191 | }); 192 | 193 | gulp.task("createProj_XM", ["createIDEProj_XM"], function() { 194 | // 如果不是小米快游戏 195 | if (platform !== "xmgame") { 196 | return; 197 | } 198 | releaseDir = path.dirname(releaseDir); 199 | projDir = path.join(releaseDir, config.xmInfo.projName); 200 | // 如果有即存项目,不再新建 201 | let isProjExist = fs.existsSync(projDir + "/node_modules") && 202 | fs.existsSync(projDir + "/sign"); 203 | if (isProjExist) { 204 | return; 205 | } 206 | // 如果IDE中有即存项目,不再新建,从IDE中拷贝 207 | let ideLastXMProjPath = path.join(IDEXMProjPath, config.xmInfo.projName); 208 | let isIDEXMProjExist = fs.existsSync(ideLastXMProjPath + "/node_modules") && 209 | fs.existsSync(ideLastXMProjPath + "/sign"); 210 | if (isIDEXMProjExist) { // 如果用的IDE并且有IDEXM目录 211 | console.log("使用IDE中的小米游戏项目,拷贝..."); 212 | // node-glob语法中,* 无法匹配 .开头的文件(夹),必须手动匹配 213 | let IDEXMProjPathStr = [`${IDEXMProjPath}/**/*.*`, `${ideLastXMProjPath}/node_modules/.bin/*.*`]; 214 | var stream = gulp.src(IDEXMProjPathStr, { base: IDEXMProjPath}); 215 | return stream.pipe(gulp.dest(releaseDir)); 216 | } 217 | // 在项目中创建小米项目 218 | return new Promise((resolve, reject) => { 219 | console.log("(proj)开始创建小米快游戏项目,请耐心等待(预计需要10分钟)..."); 220 | let cmd = `npx${commandSuffix}`; 221 | let args = ["create-quickgame", config.xmInfo.projName, `path=${releaseDir}`, 222 | `package=${config.xmInfo.package}`, `versionName=${config.xmInfo.versionName}`, 223 | `versionCode=${config.xmInfo.versionCode}`, `minPlatformVersion=${config.xmInfo.minPlatformVersion}`, 224 | `icon=/layaicon/${path.basename(config.xmInfo.icon)}`, `name=${config.xmInfo.name}`, `rebuild=true`]; 225 | console.log(JSON.stringify(args)); 226 | 227 | let cp = childProcess.spawn(cmd, args); 228 | 229 | cp.stdout.on('data', (data) => { 230 | console.log(`stdout: ${data}`); 231 | }); 232 | 233 | cp.stderr.on('data', (data) => { 234 | console.log(`stderr: ${data}`); 235 | // reject(); 236 | }); 237 | 238 | cp.on('close', (code) => { 239 | console.log(`子进程退出码:${code}`); 240 | resolve(); 241 | }); 242 | }); 243 | }); 244 | 245 | // 拷贝文件到小米快游戏 246 | gulp.task("copyFileToProj_XM", ["createProj_XM"], function() { 247 | // 如果不是小米快游戏 248 | if (platform !== "xmgame") { 249 | return; 250 | } 251 | // 将临时文件夹中的文件,拷贝到项目中去 252 | let originalDir = `${tempReleaseDir}/**/*.*`; 253 | let stream = gulp.src(originalDir); 254 | return stream.pipe(gulp.dest(path.join(projDir))); 255 | }); 256 | 257 | // 拷贝icon到小米快游戏 258 | gulp.task("copyIconToProj_XM", ["copyFileToProj_XM"], function() { 259 | // 如果不是小米快游戏 260 | if (platform !== "xmgame") { 261 | return; 262 | } 263 | let originalDir = config.xmInfo.icon; 264 | let stream = gulp.src(originalDir); 265 | return stream.pipe(gulp.dest(path.join(projDir, "layaicon"))); 266 | }); 267 | 268 | // 清除小米快游戏临时目录 269 | gulp.task("clearTempDir_XM", ["copyIconToProj_XM"], function() { 270 | // 如果不是小米快游戏 271 | if (platform !== "xmgame") { 272 | return; 273 | } 274 | // 删掉临时目录 275 | return del([tempReleaseDir], { force: true }); 276 | }); 277 | 278 | // 生成release签名(私钥文件 private.pem 和证书文件 certificate.pem ) 279 | gulp.task("generateSign_XM", ["clearTempDir_XM"], function() { 280 | // 如果不是小米快游戏 281 | if (platform !== "xmgame") { 282 | return; 283 | } 284 | if (!config.xmSign.generateSign) { 285 | return; 286 | } 287 | // https://doc.quickapp.cn/tools/compiling-tools.html 288 | return new Promise((resolve, reject) => { 289 | let cmd = "openssl"; 290 | let args = ["req", "-newkey", "rsa:2048", "-nodes", "-keyout", "private.pem", 291 | "-x509", "-days", "3650", "-out", "certificate.pem"]; 292 | let opts = { 293 | cwd: projDir, 294 | shell: true 295 | }; 296 | let cp = childProcess.spawn(cmd, args, opts); 297 | cp.stdout.on('data', (data) => { 298 | console.log(`stdout: ${data}`); 299 | }); 300 | 301 | cp.stderr.on('data', (data) => { 302 | console.log(`stderr: ${data}`); 303 | data += ""; 304 | if (data.includes("Country Name")) { 305 | cp.stdin.write(`${config.xmSign.countryName}\n`); 306 | console.log(`Country Name: ${config.xmSign.countryName}`); 307 | } else if (data.includes("Province Name")) { 308 | cp.stdin.write(`${config.xmSign.provinceName}\n`); 309 | console.log(`Province Name: ${config.xmSign.provinceName}`); 310 | } else if (data.includes("Locality Name")) { 311 | cp.stdin.write(`${config.xmSign.localityName}\n`); 312 | console.log(`Locality Name: ${config.xmSign.localityName}`); 313 | } else if (data.includes("Organization Name")) { 314 | cp.stdin.write(`${config.xmSign.orgName}\n`); 315 | console.log(`Organization Name: ${config.xmSign.orgName}`); 316 | } else if (data.includes("Organizational Unit Name")) { 317 | cp.stdin.write(`${config.xmSign.orgUnitName}\n`); 318 | console.log(`Organizational Unit Name: ${config.xmSign.orgUnitName}`); 319 | } else if (data.includes("Common Name")) { 320 | cp.stdin.write(`${config.xmSign.commonName}\n`); 321 | console.log(`Common Name: ${config.xmSign.commonName}`); 322 | } else if (data.includes("Email Address")) { 323 | cp.stdin.write(`${config.xmSign.emailAddr}\n`); 324 | console.log(`Email Address: ${config.xmSign.emailAddr}`); 325 | // cp.stdin.end(); 326 | } 327 | // reject(); 328 | }); 329 | 330 | cp.on('close', (code) => { 331 | console.log(`子进程退出码:${code}`); 332 | resolve(); 333 | }); 334 | }); 335 | }); 336 | 337 | // 拷贝sign文件到指定位置 338 | gulp.task("copySignFile_XM", ["generateSign_XM"], function() { 339 | // 如果不是小米快游戏 340 | if (platform !== "xmgame") { 341 | return; 342 | } 343 | if (config.xmSign.generateSign) { // 新生成的签名 344 | // 移动签名文件到项目中(Laya & 小米快游戏项目中) 345 | let 346 | privatePem = path.join(projDir, "private.pem"), 347 | certificatePem = path.join(projDir, "certificate.pem"); 348 | let isSignExits = fs.existsSync(privatePem) && fs.existsSync(certificatePem); 349 | if (!isSignExits) { 350 | return; 351 | } 352 | let 353 | xiaomiDest = `${projDir}/sign/release`, 354 | layaDest = `${workSpaceDir}/sign/release`; 355 | let stream = gulp.src([privatePem, certificatePem]); 356 | return stream.pipe(gulp.dest(xiaomiDest)) 357 | .pipe(gulp.dest(layaDest)); 358 | } else if (config.xmInfo.useReleaseSign && !config.xmSign.generateSign) { // 使用release签名,并且没有重新生成 359 | // 从项目中将签名拷贝到小米快游戏项目中 360 | let 361 | privatePem = path.join(workSpaceDir, "sign", "release", "private.pem"), 362 | certificatePem = path.join(workSpaceDir, "sign", "release", "certificate.pem"); 363 | let isSignExits = fs.existsSync(privatePem) && fs.existsSync(certificatePem); 364 | if (!isSignExits) { 365 | return; 366 | } 367 | let 368 | xiaomiDest = `${projDir}/sign/release`; 369 | let stream = gulp.src([privatePem, certificatePem]); 370 | return stream.pipe(gulp.dest(xiaomiDest)); 371 | } 372 | }); 373 | 374 | gulp.task("deleteSignFile_XM", ["copySignFile_XM"], function() { 375 | // 如果不是小米快游戏 376 | if (platform !== "xmgame") { 377 | return; 378 | } 379 | if (config.xmSign.generateSign) { // 新生成的签名 380 | let 381 | privatePem = path.join(projDir, "private.pem"), 382 | certificatePem = path.join(projDir, "certificate.pem"); 383 | return del([privatePem, certificatePem], { force: true }); 384 | } 385 | }); 386 | 387 | gulp.task("modifyFile_XM", ["deleteSignFile_XM"], function() { 388 | // 如果不是小米快游戏 389 | if (platform !== "xmgame") { 390 | return; 391 | } 392 | // 修改manifest.json文件 393 | let manifestPath = path.join(projDir, "manifest.json"); 394 | if (!fs.existsSync(manifestPath)) { 395 | return; 396 | } 397 | let manifestContent = fs.readFileSync(manifestPath, "utf8"); 398 | let manifestJson = JSON.parse(manifestContent); 399 | manifestJson.package = config.xmInfo.package; 400 | manifestJson.name = config.xmInfo.name; 401 | manifestJson.orientation = config.xmInfo.orientation; 402 | manifestJson.versionName = config.xmInfo.versionName; 403 | manifestJson.versionCode = config.xmInfo.versionCode; 404 | manifestJson.minPlatformVersion = config.xmInfo.minPlatformVersion; 405 | manifestJson.icon = `/layaicon/${path.basename(config.xmInfo.icon)}`; 406 | fs.writeFileSync(manifestPath, JSON.stringify(manifestJson, null, 4), "utf8"); 407 | 408 | // 修改main.js文件 409 | let content = 'require("./qg-adapter.js");\nrequire("./libs/laya.xmmini.js");\nrequire("./index.js");'; 410 | let mainJsPath = path.join(projDir, "main.js"); 411 | fs.writeFileSync(mainJsPath, content, "utf8"); 412 | 413 | // 小米项目,修改index.js 414 | let filePath = path.join(projDir, "index.js"); 415 | if (!fs.existsSync(filePath)) { 416 | return; 417 | } 418 | let fileContent = fs.readFileSync(filePath, "utf8"); 419 | fileContent = fileContent.replace(/loadLib(\(['"])/gm, "require$1./"); 420 | fs.writeFileSync(filePath, fileContent, "utf8"); 421 | }) 422 | 423 | // 打包rpk 424 | gulp.task("buildRPK_XM", ["modifyFile_XM"], function() { 425 | // 如果不是小米快游戏 426 | if (platform !== "xmgame") { 427 | return; 428 | } 429 | // 在小米轻游戏项目目录中执行: 430 | // npm run build || npm run release 431 | let cmdStr = "build"; 432 | if (config.xmInfo.useReleaseSign) { 433 | cmdStr = "release"; 434 | } 435 | return new Promise((resolve, reject) => { 436 | let cmd = `npm${commandSuffix}`; 437 | let args = ["run", cmdStr]; 438 | let opts = { 439 | cwd: projDir 440 | }; 441 | let cp = childProcess.spawn(cmd, args, opts); 442 | // let cp = childProcess.spawn(`npx${commandSuffix}`, ['-v']); 443 | cp.stdout.on('data', (data) => { 444 | console.log(`stdout: ${data}`); 445 | }); 446 | 447 | cp.stderr.on('data', (data) => { 448 | console.log(`stderr: ${data}`); 449 | // reject(); 450 | }); 451 | 452 | cp.on('close', (code) => { 453 | console.log(`子进程退出码:${code}`); 454 | resolve(); 455 | }); 456 | }); 457 | }); 458 | 459 | gulp.task("showQRCode_XM", ["buildRPK_XM"], function() { 460 | // 如果不是小米快游戏 461 | if (platform !== "xmgame") { 462 | return; 463 | } 464 | // 在小米轻游戏项目目录中执行: 465 | // npm run server 466 | return new Promise((resolve, reject) => { 467 | let cmd = `npm${commandSuffix}`; 468 | let args = ["run", "server"]; 469 | let opts = { 470 | cwd: projDir 471 | }; 472 | let cp = childProcess.spawn(cmd, args, opts); 473 | // let cp = childProcess.spawn(`npx${commandSuffix}`, ['-v']); 474 | cp.stdout.on('data', (data) => { 475 | console.log(`${data}`); 476 | // 输出pid,macos要用: macos无法kill进程树,也无法执行命令获取3000端口pid(没有查询权限),导致无法kill这个进程 477 | console.log('xm_qrcode_pid:' + cp.pid); 478 | }); 479 | 480 | cp.stderr.on('data', (data) => { 481 | console.log(`stderr: ${data}`); 482 | // reject(); 483 | }); 484 | 485 | cp.on('close', (code) => { 486 | console.log(`子进程退出码:${code}`); 487 | resolve(); 488 | }); 489 | }); 490 | }); 491 | 492 | 493 | gulp.task("buildXiaomiProj", ["showQRCode_XM"], function() { 494 | console.log("all tasks completed"); 495 | }); -------------------------------------------------------------------------------- /.laya/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "autoHeader": { 3 | "format": { 4 | "startWith": "/**", 5 | "middleWith": "*", 6 | "endWith": "*/", 7 | "headerPrefix": "@", 8 | }, 9 | "header": { 10 | "Description": " ", 11 | "Author": "lzh", 12 | "Date": { 13 | "type": "createTime", 14 | "format": "YYYY-MM-DD HH:mm:ss", 15 | }, 16 | "Last Modified by": { 17 | "type": "modifier", 18 | "value": "lzh", 19 | }, 20 | "Last Modified time": { 21 | "type": "modifyTime", 22 | "format": "YYYY-MM-DD HH:mm:ss" 23 | }, 24 | "copyright": "youai" 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /bin/DP1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lizenghua/JoyStick/f6b04af496d90c5a15b5f17223ad85c2f9234418/bin/DP1.png -------------------------------------------------------------------------------- /bin/fileconfig.json: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /bin/game.js: -------------------------------------------------------------------------------- 1 | if ((typeof swan !== 'undefined') && (typeof swanGlobal !== 'undefined')) { 2 | require("swan-game-adapter.js"); 3 | require("libs/laya.bdmini.js"); 4 | } else if (typeof wx!=="undefined") { 5 | require("weapp-adapter.js"); 6 | require("libs/laya.wxmini.js"); 7 | } 8 | window.loadLib = require; 9 | require("index.js"); -------------------------------------------------------------------------------- /bin/game.json: -------------------------------------------------------------------------------- 1 | { 2 | "deviceOrientation": "portrait", 3 | "showStatusBar": false, 4 | "networkTimeout": { 5 | "request": 10000, 6 | "connectSocket": 10000, 7 | "uploadFile": 10000, 8 | "downloadFile": 10000 9 | } 10 | } -------------------------------------------------------------------------------- /bin/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 |PathFinding
类用于创建寻路。
8 | */
9 | //class laya.d3.component.PathFind extends laya.components.Component
10 | var PathFind=(function(_super){
11 | function PathFind(){
12 | /**@private */
13 | this._meshTerrainSprite3D=null;
14 | /**@private */
15 | this._finder=null;
16 | /**@private */
17 | this._setting=null;
18 | /**寻路网格。*/
19 | this.grid=null;
20 | PathFind.__super.call(this);
21 | }
22 |
23 | __class(PathFind,'laya.d3.component.PathFind',_super);
24 | var __proto=PathFind.prototype;
25 | /**
26 | *@private
27 | *初始化载入蒙皮动画组件。
28 | *@param owner 所属精灵对象。
29 | */
30 | __proto._onAdded=function(){
31 | if (! (this.owner instanceof laya.d3.core.MeshTerrainSprite3D ))
32 | throw new Error("PathFinding: The owner must MeshTerrainSprite3D!");
33 | this._meshTerrainSprite3D=this.owner;
34 | }
35 |
36 | /**
37 | *寻找路径。
38 | *@param startX 开始X。
39 | *@param startZ 开始Z。
40 | *@param endX 结束X。
41 | *@param endZ 结束Z。
42 | *@return 路径。
43 | */
44 | __proto.findPath=function(startX,startZ,endX,endZ){
45 | var minX=this._meshTerrainSprite3D.minX;
46 | var minZ=this._meshTerrainSprite3D.minZ;
47 | var cellX=this._meshTerrainSprite3D.width / this.grid.width;
48 | var cellZ=this._meshTerrainSprite3D.depth / this.grid.height;
49 | var halfCellX=cellX / 2;
50 | var halfCellZ=cellZ / 2;
51 | var gridStartX=Math.floor((startX-minX)/ cellX);
52 | var gridStartZ=Math.floor((startZ-minZ)/ cellZ);
53 | var gridEndX=Math.floor((endX-minX)/ cellX);
54 | var gridEndZ=Math.floor((endZ-minZ)/ cellZ);
55 | var boundWidth=this.grid.width-1;
56 | var boundHeight=this.grid.height-1;
57 | (gridStartX > boundWidth)&& (gridStartX=boundWidth);
58 | (gridStartZ > boundHeight)&& (gridStartZ=boundHeight);
59 | (gridStartX < 0)&& (gridStartX=0);
60 | (gridStartZ < 0)&& (gridStartZ=0);
61 | (gridEndX > boundWidth)&& (gridEndX=boundWidth);
62 | (gridEndZ > boundHeight)&& (gridEndZ=boundHeight);
63 | (gridEndX < 0)&& (gridEndX=0);
64 | (gridEndZ < 0)&& (gridEndZ=0);
65 | var path=this._finder.findPath(gridStartX,gridStartZ,gridEndX,gridEndZ,this.grid);
66 | this.grid.reset();
67 | for (var i=1;i < path.length-1;i++){
68 | var gridPos=path[i];
69 | gridPos[0]=gridPos[0] *cellX+halfCellX+minX;
70 | gridPos[1]=gridPos[1] *cellZ+halfCellZ+minZ;
71 | }
72 | if (path.length==1){
73 | path[0][0]=endX;
74 | path[0][1]=endX;
75 | }else if (path.length > 1){
76 | path[0][0]=startX;
77 | path[0][1]=startZ;
78 | path[path.length-1][0]=endX;
79 | path[path.length-1][1]=endZ;
80 | }
81 | return path;
82 | }
83 |
84 | /**
85 | *设置寻路设置。
86 | *@param value 寻路设置。
87 | */
88 | /**
89 | *获取寻路设置。
90 | *@return 寻路设置。
91 | */
92 | __getset(0,__proto,'setting',function(){
93 | return this._setting;
94 | },function(value){
95 | (value)&& (this._finder=new PathFinding.finders.AStarFinder(value));
96 | this._setting=value;
97 | });
98 |
99 | return PathFind;
100 | })(Component)
101 |
102 |
103 |
104 | })(window,document,Laya);
105 |
--------------------------------------------------------------------------------
/bin/libs/laya.device.js:
--------------------------------------------------------------------------------
1 |
2 | (function(window,document,Laya){
3 | var __un=Laya.un,__uns=Laya.uns,__static=Laya.static,__class=Laya.class,__getset=Laya.getset,__newvec=Laya.__newvec;
4 |
5 | var Bitmap=laya.resource.Bitmap,Browser=laya.utils.Browser,Event=laya.events.Event,EventDispatcher=laya.events.EventDispatcher;
6 | var Handler=laya.utils.Handler,LayaGL=laya.layagl.LayaGL,Rectangle=laya.maths.Rectangle,Render=laya.renders.Render;
7 | var Sprite=laya.display.Sprite,Stage=laya.display.Stage,Texture=laya.resource.Texture,Utils=laya.utils.Utils;
8 | var WebGL=laya.webgl.WebGL,WebGLContext=laya.webgl.WebGLContext;
9 | /**
10 | *使用前可用supported
查看浏览器支持。
11 | */
12 | //class laya.device.geolocation.Geolocation
13 | var Geolocation=(function(){
14 | function Geolocation(){}
15 | __class(Geolocation,'laya.device.geolocation.Geolocation');
16 | Geolocation.getCurrentPosition=function(onSuccess,onError){
17 | Geolocation.navigator.geolocation.getCurrentPosition(function(pos){
18 | Geolocation.position.setPosition(pos);
19 | onSuccess.runWith(Geolocation.position);
20 | },
21 | function(error){
22 | onError.runWith(error);
23 | },{
24 | enableHighAccuracy :laya.device.geolocation.Geolocation.enableHighAccuracy,
25 | timeout :laya.device.geolocation.Geolocation.timeout,
26 | maximumAge :laya.device.geolocation.Geolocation.maximumAge
27 | });
28 | }
29 |
30 | Geolocation.watchPosition=function(onSuccess,onError){
31 | return Geolocation.navigator.geolocation.watchPosition(function(pos){
32 | Geolocation.position.setPosition(pos);
33 | onSuccess.runWith(Geolocation.position);
34 | },
35 | function(error){
36 | onError.runWith(error);
37 | },{
38 | enableHighAccuracy :Geolocation.enableHighAccuracy,
39 | timeout :Geolocation.timeout,
40 | maximumAge :Geolocation.maximumAge
41 | });
42 | }
43 |
44 | Geolocation.clearWatch=function(id){
45 | Geolocation.navigator.geolocation.clearWatch(id);
46 | }
47 |
48 | Geolocation.PERMISSION_DENIED=1;
49 | Geolocation.POSITION_UNAVAILABLE=2;
50 | Geolocation.TIMEOUT=3;
51 | Geolocation.enableHighAccuracy=false;
52 | Geolocation.maximumAge=0;
53 | __static(Geolocation,
54 | ['navigator',function(){return this.navigator=Browser.window.navigator;},'position',function(){return this.position=new GeolocationInfo();},'supported',function(){return this.supported=!!Geolocation.navigator.geolocation;},'timeout',function(){return this.timeout=1E10;}
55 | ]);
56 | return Geolocation;
57 | })()
58 |
59 |
60 | /**
61 | *Media用于捕捉摄像头和麦克风。可以捕捉任意之一,或者同时捕捉两者。getCamera
前可以使用supported()
检查当前浏览器是否支持。
62 | *NOTE:
63 | *目前Media在移动平台只支持Android,不支持IOS。只可在FireFox完整地使用,Chrome测试时无法捕捉视频。
64 | */ 65 | //class laya.device.media.Media 66 | var Media=(function(){ 67 | function Media(){} 68 | __class(Media,'laya.device.media.Media'); 69 | Media.supported=function(){ 70 | return !!Browser.window.navigator.getUserMedia; 71 | } 72 | 73 | Media.getMedia=function(options,onSuccess,onError){ 74 | if (Browser.window.navigator.getUserMedia){ 75 | Browser.window.navigator.getUserMedia(options,function(stream){ 76 | onSuccess.runWith(Browser.window.URL.createObjectURL(stream)); 77 | },function(err){ 78 | onError.runWith(err); 79 | }); 80 | } 81 | } 82 | 83 | Media.__init$=function(){ 84 | /*__JS__ */navigator.getUserMedia=navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia;; 85 | } 86 | 87 | return Media; 88 | })() 89 | 90 | 91 | /** 92 | *加速度x/y/z的单位均为m/s²。 93 | *在硬件(陀螺仪)不支持的情况下,alpha、beta和gamma值为null。 94 | * 95 | *@author Survivor 96 | */ 97 | //class laya.device.motion.AccelerationInfo 98 | var AccelerationInfo=(function(){ 99 | function AccelerationInfo(){ 100 | /** 101 | *x轴上的加速度值。 102 | */ 103 | this.x=NaN; 104 | /** 105 | *y轴上的加速度值。 106 | */ 107 | this.y=NaN; 108 | /** 109 | *z轴上的加速度值。 110 | */ 111 | this.z=NaN; 112 | } 113 | 114 | __class(AccelerationInfo,'laya.device.motion.AccelerationInfo'); 115 | return AccelerationInfo; 116 | })() 117 | 118 | 119 | //class laya.device.geolocation.GeolocationInfo 120 | var GeolocationInfo=(function(){ 121 | function GeolocationInfo(){ 122 | this.pos=null; 123 | this.coords=null; 124 | } 125 | 126 | __class(GeolocationInfo,'laya.device.geolocation.GeolocationInfo'); 127 | var __proto=GeolocationInfo.prototype; 128 | __proto.setPosition=function(pos){ 129 | this.pos=pos; 130 | this.coords=pos.coords; 131 | } 132 | 133 | __getset(0,__proto,'heading',function(){ 134 | return this.coords.heading; 135 | }); 136 | 137 | __getset(0,__proto,'latitude',function(){ 138 | return this.coords.latitude; 139 | }); 140 | 141 | __getset(0,__proto,'altitudeAccuracy',function(){ 142 | return this.coords.altitudeAccuracy; 143 | }); 144 | 145 | __getset(0,__proto,'longitude',function(){ 146 | return this.coords.longitude; 147 | }); 148 | 149 | __getset(0,__proto,'altitude',function(){ 150 | return this.coords.altitude; 151 | }); 152 | 153 | __getset(0,__proto,'accuracy',function(){ 154 | return this.coords.accuracy; 155 | }); 156 | 157 | __getset(0,__proto,'speed',function(){ 158 | return this.coords.speed; 159 | }); 160 | 161 | __getset(0,__proto,'timestamp',function(){ 162 | return this.pos.timestamp; 163 | }); 164 | 165 | return GeolocationInfo; 166 | })() 167 | 168 | 169 | /** 170 | *保存旋转信息的类。请勿修改本类的属性。 171 | *@author Survivor 172 | */ 173 | //class laya.device.motion.RotationInfo 174 | var RotationInfo=(function(){ 175 | function RotationInfo(){ 176 | /** 177 | *178 | *指示设备是否可以提供绝对方位数据(指向地球坐标系),或者设备决定的任意坐标系。 179 | *关于坐标系参见https://developer.mozilla.org/en-US/docs/Web/Guide/Events/Orientation_and_motion_data_explained。 180 | *
181 | *需要注意的是,IOS环境下,该值始终为false。即使如此,你依旧可以从alpha
中取得正确的值。
182 | */
183 | this.absolute=false;
184 | /**
185 | *Z轴旋转角度,其值范围从0至360。
186 | *若absolute
为true或者在IOS中,alpha值是从北方到当前设备方向的角度值。
187 | */
188 | this.alpha=NaN;
189 | /**
190 | *X轴旋转角度,其值范围从-180至180。代表设备从前至后的运动。
191 | */
192 | this.beta=NaN;
193 | /**
194 | *Y轴旋转角度,其值范围从-90至90。代表设备从左至右的运动。
195 | */
196 | this.gamma=NaN;
197 | /**
198 | *罗盘数据的精确度(角度)。仅IOS可用。
199 | */
200 | this.compassAccuracy=NaN;
201 | }
202 |
203 | __class(RotationInfo,'laya.device.motion.RotationInfo');
204 | return RotationInfo;
205 | })()
206 |
207 |
208 | /**
209 | *使用Gyroscope.instance获取唯一的Gyroscope引用,请勿调用构造函数。
210 | *
211 | *
212 | *listen()的回调处理器接受两个参数:
213 | *function onOrientationChange(absolute:Boolean,info:RotationInfo):void
214 | *
RotationInfo
类型参数,保存设备的旋转值。221 | *浏览器兼容性参见:http://caniuse.com/#search=deviceorientation 222 | *
223 | */ 224 | //class laya.device.motion.Gyroscope extends laya.events.EventDispatcher 225 | var Gyroscope=(function(_super){ 226 | function Gyroscope(singleton){ 227 | Gyroscope.__super.call(this); 228 | /*__JS__ */this.onDeviceOrientationChange=this.onDeviceOrientationChange.bind(this); 229 | } 230 | 231 | __class(Gyroscope,'laya.device.motion.Gyroscope',_super); 232 | var __proto=Gyroscope.prototype; 233 | /** 234 | *监视陀螺仪运动。 235 | *@param observer 回调函数接受一个Boolean类型的absolute
和GyroscopeInfo
类型参数。
236 | */
237 | __proto.on=function(type,caller,listener,args){
238 | _super.prototype.on.call(this,type,caller,listener,args);
239 | Browser.window.addEventListener('deviceorientation',this.onDeviceOrientationChange);
240 | return this;
241 | }
242 |
243 | /**
244 | *取消指定处理器对陀螺仪的监视。
245 | *@param observer
246 | */
247 | __proto.off=function(type,caller,listener,onceOnly){
248 | (onceOnly===void 0)&& (onceOnly=false);
249 | if (!this.hasListener(type))
250 | Browser.window.removeEventListener('deviceorientation',this.onDeviceOrientationChange);
251 | return _super.prototype.off.call(this,type,caller,listener,onceOnly);
252 | }
253 |
254 | __proto.onDeviceOrientationChange=function(e){
255 | Gyroscope.info.alpha=e.alpha;
256 | Gyroscope.info.beta=e.beta;
257 | Gyroscope.info.gamma=e.gamma;
258 | if (e.webkitCompassHeading){
259 | Gyroscope.info.alpha=e.webkitCompassHeading *-1;
260 | Gyroscope.info.compassAccuracy=e.webkitCompassAccuracy;
261 | }
262 | this.event(/*laya.events.Event.CHANGE*/"change",[e.absolute,Gyroscope.info]);
263 | }
264 |
265 | __getset(1,Gyroscope,'instance',function(){Gyroscope._instance=Gyroscope._instance|| new Gyroscope(0);
266 | return Gyroscope._instance;
267 | },laya.events.EventDispatcher._$SET_instance);
268 |
269 | Gyroscope._instance=null;
270 | __static(Gyroscope,
271 | ['info',function(){return this.info=new RotationInfo();}
272 | ]);
273 | return Gyroscope;
274 | })(EventDispatcher)
275 |
276 |
277 | /**
278 | *Shake只能在支持此操作的设备上有效。
279 | *
280 | *@author Survivor
281 | */
282 | //class laya.device.Shake extends laya.events.EventDispatcher
283 | var Shake=(function(_super){
284 | function Shake(){
285 | this.throushold=0;
286 | this.shakeInterval=0;
287 | this.callback=null;
288 | this.lastX=NaN;
289 | this.lastY=NaN;
290 | this.lastZ=NaN;
291 | this.lastMillSecond=NaN;
292 | Shake.__super.call(this);
293 | }
294 |
295 | __class(Shake,'laya.device.Shake',_super);
296 | var __proto=Shake.prototype;
297 | /**
298 | *开始响应设备摇晃。
299 | *@param throushold 响应的瞬时速度阈值,轻度摇晃的值约在5~10间。
300 | *@param timeout 设备摇晃的响应间隔时间。
301 | *@param callback 在设备摇晃触发时调用的处理器。
302 | */
303 | __proto.start=function(throushold,interval){
304 | this.throushold=throushold;
305 | this.shakeInterval=interval;
306 | this.lastX=this.lastY=this.lastZ=NaN;
307 | Accelerator.instance.on(/*laya.events.Event.CHANGE*/"change",this,this.onShake);
308 | }
309 |
310 | /**
311 | *停止响应设备摇晃。
312 | */
313 | __proto.stop=function(){
314 | Accelerator.instance.off(/*laya.events.Event.CHANGE*/"change",this,this.onShake);
315 | }
316 |
317 | __proto.onShake=function(acceleration,accelerationIncludingGravity,rotationRate,interval){
318 | if(isNaN(this.lastX)){
319 | this.lastX=accelerationIncludingGravity.x;
320 | this.lastY=accelerationIncludingGravity.y;
321 | this.lastZ=accelerationIncludingGravity.z;
322 | this.lastMillSecond=Browser.now();
323 | return;
324 | };
325 | var deltaX=Math.abs(this.lastX-accelerationIncludingGravity.x);
326 | var deltaY=Math.abs(this.lastY-accelerationIncludingGravity.y);
327 | var deltaZ=Math.abs(this.lastZ-accelerationIncludingGravity.z);
328 | if(this.isShaked(deltaX,deltaY,deltaZ)){
329 | var deltaMillSecond=Browser.now()-this.lastMillSecond;
330 | if (deltaMillSecond > this.shakeInterval){
331 | this.event(/*laya.events.Event.CHANGE*/"change");
332 | this.lastMillSecond=Browser.now();
333 | }
334 | }
335 | this.lastX=accelerationIncludingGravity.x;
336 | this.lastY=accelerationIncludingGravity.y;
337 | this.lastZ=accelerationIncludingGravity.z;
338 | }
339 |
340 | // 通过任意两个分量判断是否满足摇晃设定。
341 | __proto.isShaked=function(deltaX,deltaY,deltaZ){
342 | return (deltaX > this.throushold && deltaY > this.throushold)||
343 | (deltaX > this.throushold && deltaZ > this.throushold)||
344 | (deltaY > this.throushold && deltaZ > this.throushold)
345 | }
346 |
347 | __getset(1,Shake,'instance',function(){Shake._instance=Shake._instance|| new Shake();
348 | return Shake._instance;
349 | },laya.events.EventDispatcher._$SET_instance);
350 |
351 | Shake._instance=null;
352 | return Shake;
353 | })(EventDispatcher)
354 |
355 |
356 | /**
357 | *Accelerator.instance获取唯一的Accelerator引用,请勿调用构造函数。
358 | *
359 | *360 | *listen()的回调处理器接受四个参数: 361 | *
369 | *NOTE
370 | *如,rotationRate的alpha在apple和moz文档中都是z轴旋转角度,但是实测是x轴旋转角度。为了使各属性表示的值与文档所述相同,实际值与其他属性进行了对调。
371 | *其中:
372 | *
Video
将视频显示到Canvas上。Video
可能不会在所有浏览器有效。
487 | *关于Video支持的所有事件参见:http://www.w3school.com.cn/tags/html_ref_audio_video_dom.asp。
488 | *
489 | *注意:
490 | *在PC端可以在任何时机调用play()
因此,可以在程序开始运行时就使Video开始播放。但是在移动端,只有在用户第一次触碰屏幕后才可以调用play(),所以移动端不可能在程序开始运行时就自动开始播放Video。
491 | *
MDN Video链接: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/video
494 | */ 495 | //class laya.device.media.Video extends laya.display.Sprite 496 | var Video=(function(_super){ 497 | function Video(width,height){ 498 | this.htmlVideo=null; 499 | this.videoElement=null; 500 | this.internalTexture=null; 501 | (width===void 0)&& (width=320); 502 | (height===void 0)&& (height=240); 503 | Video.__super.call(this); 504 | this.htmlVideo=new WebGLVideo(); 505 | this.videoElement=this.htmlVideo.getVideo(); 506 | this.videoElement.layaTarget=this; 507 | this.internalTexture=new Texture(this.htmlVideo); 508 | this.videoElement.addEventListener("abort",Video.onAbort); 509 | this.videoElement.addEventListener("canplay",Video.onCanplay); 510 | this.videoElement.addEventListener("canplaythrough",Video.onCanplaythrough); 511 | this.videoElement.addEventListener("durationchange",Video.onDurationchange); 512 | this.videoElement.addEventListener("emptied",Video.onEmptied); 513 | this.videoElement.addEventListener("error",Video.onError); 514 | this.videoElement.addEventListener("loadeddata",Video.onLoadeddata); 515 | this.videoElement.addEventListener("loadedmetadata",Video.onLoadedmetadata); 516 | this.videoElement.addEventListener("loadstart",Video.onLoadstart); 517 | this.videoElement.addEventListener("pause",Video.onPause); 518 | this.videoElement.addEventListener("play",Video.onPlay); 519 | this.videoElement.addEventListener("playing",Video.onPlaying); 520 | this.videoElement.addEventListener("progress",Video.onProgress); 521 | this.videoElement.addEventListener("ratechange",Video.onRatechange); 522 | this.videoElement.addEventListener("seeked",Video.onSeeked); 523 | this.videoElement.addEventListener("seeking",Video.onSeeking); 524 | this.videoElement.addEventListener("stalled",Video.onStalled); 525 | this.videoElement.addEventListener("suspend",Video.onSuspend); 526 | this.videoElement.addEventListener("timeupdate",Video.onTimeupdate); 527 | this.videoElement.addEventListener("volumechange",Video.onVolumechange); 528 | this.videoElement.addEventListener("waiting",Video.onWaiting); 529 | this.videoElement.addEventListener("ended",this.onPlayComplete['bind'](this)); 530 | this.size(width,height); 531 | if (Browser.onMobile){ 532 | /*__JS__ */this.onDocumentClick=this.onDocumentClick.bind(this); 533 | Browser.document.addEventListener("touchend",this.onDocumentClick); 534 | } 535 | } 536 | 537 | __class(Video,'laya.device.media.Video',_super); 538 | var __proto=Video.prototype; 539 | __proto.onPlayComplete=function(e){ 540 | this.event("ended"); 541 | if(!Render.isConchApp || !this.videoElement || !this.videoElement.loop) 542 | Laya.timer.clear(this,this.renderCanvas); 543 | } 544 | 545 | /** 546 | *设置播放源。 547 | *@param url 播放源路径。 548 | */ 549 | __proto.load=function(url){ 550 | if (url.indexOf("blob:")==0) 551 | this.videoElement.src=url; 552 | else 553 | this.htmlVideo.setSource(url,laya.device.media.Video.MP4); 554 | } 555 | 556 | /** 557 | *开始播放视频。 558 | */ 559 | __proto.play=function(){ 560 | this.videoElement.play(); 561 | Laya.timer.frameLoop(1,this,this.renderCanvas); 562 | } 563 | 564 | /** 565 | *暂停视频播放。 566 | */ 567 | __proto.pause=function(){ 568 | this.videoElement.pause(); 569 | Laya.timer.clear(this,this.renderCanvas); 570 | } 571 | 572 | /** 573 | *重新加载视频。 574 | */ 575 | __proto.reload=function(){ 576 | this.videoElement.load(); 577 | } 578 | 579 | /** 580 | *检测是否支持播放指定格式视频。 581 | *@param type 参数为Video.MP4 / Video.OGG / Video.WEBM之一。 582 | *@return 表示支持的级别。可能的值: 583 | *buffered.length返回缓冲范围个数。如获取第一个缓冲范围则是buffered.start(0)和buffered.end(0)。以秒计。
682 | *@return TimeRanges(JS)对象 683 | */ 684 | __getset(0,__proto,'buffered',function(){ 685 | return this.videoElement.buffered; 686 | }); 687 | 688 | /** 689 | *获取视频源尺寸。ready事件触发后可用。 690 | */ 691 | __getset(0,__proto,'videoWidth',function(){ 692 | return this.videoElement.videoWidth; 693 | }); 694 | 695 | /** 696 | *获取当前播放源路径。 697 | */ 698 | __getset(0,__proto,'currentSrc',function(){ 699 | return this.videoElement.currentSrc; 700 | }); 701 | 702 | /** 703 | *设置和获取当前播放头位置。 704 | */ 705 | __getset(0,__proto,'currentTime',function(){ 706 | return this.videoElement.currentTime; 707 | },function(value){ 708 | this.videoElement.currentTime=value; 709 | this.renderCanvas(); 710 | }); 711 | 712 | /** 713 | *返回音频/视频的播放是否已结束 714 | */ 715 | __getset(0,__proto,'ended',function(){ 716 | return this.videoElement.ended; 717 | }); 718 | 719 | /** 720 | *设置和获取当前音量。 721 | */ 722 | __getset(0,__proto,'volume',function(){ 723 | return this.videoElement.volume; 724 | },function(value){ 725 | this.videoElement.volume=value; 726 | }); 727 | 728 | __getset(0,__proto,'videoHeight',function(){ 729 | return this.videoElement.videoHeight; 730 | }); 731 | 732 | /** 733 | *表示视频元素的就绪状态: 734 | *只有 Google Chrome 和 Safari 支持 playbackRate 属性。
801 | */ 802 | __getset(0,__proto,'playbackRate',function(){ 803 | return this.videoElement.playbackRate; 804 | },function(value){ 805 | this.videoElement.playbackRate=value; 806 | }); 807 | 808 | /** 809 | *获取和设置静音状态。 810 | */ 811 | __getset(0,__proto,'muted',function(){ 812 | return this.videoElement.muted; 813 | },function(value){ 814 | this.videoElement.muted=value; 815 | }); 816 | 817 | /** 818 | *返回视频是否暂停 819 | */ 820 | __getset(0,__proto,'paused',function(){ 821 | return this.videoElement.paused; 822 | }); 823 | 824 | /** 825 | *preload 属性设置或返回是否在页面加载后立即加载视频。可赋值如下: 826 | *ParticleTemplateBase
类是粒子模板基类
14 | *
15 | */
16 | //class laya.particle.ParticleTemplateBase
17 | var ParticleTemplateBase=(function(){
18 | function ParticleTemplateBase(){
19 | /**
20 | *粒子配置数据
21 | */
22 | this.settings=null;
23 | /**
24 | *粒子贴图
25 | */
26 | this.texture=null;
27 | }
28 |
29 | __class(ParticleTemplateBase,'laya.particle.ParticleTemplateBase');
30 | var __proto=ParticleTemplateBase.prototype;
31 | /**
32 | *添加一个粒子
33 | *@param position 粒子位置
34 | *@param velocity 粒子速度
35 | *
36 | */
37 | __proto.addParticleArray=function(position,velocity){}
38 | return ParticleTemplateBase;
39 | })()
40 |
41 |
42 | /**
43 | *EmitterBase
类是粒子发射器类
44 | */
45 | //class laya.particle.emitter.EmitterBase
46 | var EmitterBase=(function(){
47 | function EmitterBase(){
48 | /**
49 | *积累的帧时间
50 | */
51 | this._frameTime=0;
52 | /**
53 | *粒子发射速率
54 | */
55 | this._emissionRate=60;
56 | /**
57 | *当前剩余发射时间
58 | */
59 | this._emissionTime=0;
60 | /**
61 | *发射粒子最小时间间隔
62 | */
63 | this.minEmissionTime=1 / 60;
64 | /**@private */
65 | this._particleTemplate=null;
66 | }
67 |
68 | __class(EmitterBase,'laya.particle.emitter.EmitterBase');
69 | var __proto=EmitterBase.prototype;
70 | /**
71 | *开始发射粒子
72 | *@param duration 发射持续的时间(秒)
73 | */
74 | __proto.start=function(duration){
75 | (duration===void 0)&& (duration=Number.MAX_VALUE);
76 | if (this._emissionRate !=0)
77 | this._emissionTime=duration;
78 | }
79 |
80 | /**
81 | *停止发射粒子
82 | *@param clearParticles 是否清理当前的粒子
83 | */
84 | __proto.stop=function(){
85 | this._emissionTime=0;
86 | }
87 |
88 | /**
89 | *清理当前的活跃粒子
90 | *@param clearTexture 是否清理贴图数据,若清除贴图数据将无法再播放
91 | */
92 | __proto.clear=function(){
93 | this._emissionTime=0;
94 | }
95 |
96 | /**
97 | *发射一个粒子
98 | *
99 | */
100 | __proto.emit=function(){}
101 | /**
102 | *时钟前进
103 | *@param passedTime 前进时间
104 | *
105 | */
106 | __proto.advanceTime=function(passedTime){
107 | (passedTime===void 0)&& (passedTime=1);
108 | this._emissionTime-=passedTime;
109 | if (this._emissionTime < 0)return;
110 | this._frameTime+=passedTime;
111 | if (this._frameTime < this.minEmissionTime)return;
112 | while (this._frameTime > this.minEmissionTime){
113 | this._frameTime-=this.minEmissionTime;
114 | this.emit();
115 | }
116 | }
117 |
118 | /**
119 | *设置粒子粒子模板
120 | *@param particleTemplate 粒子模板
121 | *
122 | */
123 | __getset(0,__proto,'particleTemplate',null,function(particleTemplate){
124 | this._particleTemplate=particleTemplate;
125 | });
126 |
127 | /**
128 | *设置粒子发射速率
129 | *@param emissionRate 粒子发射速率 (个/秒)
130 | */
131 | /**
132 | *获取粒子发射速率
133 | *@return 发射速率 粒子发射速率 (个/秒)
134 | */
135 | __getset(0,__proto,'emissionRate',function(){
136 | return this._emissionRate;
137 | },function(_emissionRate){
138 | if (_emissionRate <=0)return;
139 | this._emissionRate=_emissionRate;
140 | (_emissionRate > 0)&& (this.minEmissionTime=1 / _emissionRate);
141 | });
142 |
143 | return EmitterBase;
144 | })()
145 |
146 |
147 | /**
148 | *@private
149 | */
150 | //class laya.particle.ParticleEmitter
151 | var ParticleEmitter=(function(){
152 | function ParticleEmitter(templet,particlesPerSecond,initialPosition){
153 | this._templet=null;
154 | this._timeBetweenParticles=NaN;
155 | this._previousPosition=null;
156 | this._timeLeftOver=0;
157 | this._tempVelocity=new Float32Array([0,0,0]);
158 | this._tempPosition=new Float32Array([0,0,0]);
159 | this._templet=templet;
160 | this._timeBetweenParticles=1.0 / particlesPerSecond;
161 | this._previousPosition=initialPosition;
162 | }
163 |
164 | __class(ParticleEmitter,'laya.particle.ParticleEmitter');
165 | var __proto=ParticleEmitter.prototype;
166 | __proto.update=function(elapsedTime,newPosition){
167 | elapsedTime=elapsedTime / 1000;
168 | if (elapsedTime > 0){
169 | MathUtil.subtractVector3(newPosition,this._previousPosition,this._tempVelocity);
170 | MathUtil.scaleVector3(this._tempVelocity,1 / elapsedTime,this._tempVelocity);
171 | var timeToSpend=this._timeLeftOver+elapsedTime;
172 | var currentTime=-this._timeLeftOver;
173 | while (timeToSpend > this._timeBetweenParticles){
174 | currentTime+=this._timeBetweenParticles;
175 | timeToSpend-=this._timeBetweenParticles;
176 | MathUtil.lerpVector3(this._previousPosition,newPosition,currentTime / elapsedTime,this._tempPosition);
177 | this._templet.addParticleArray(this._tempPosition,this._tempVelocity);
178 | }
179 | this._timeLeftOver=timeToSpend;
180 | }
181 | this._previousPosition[0]=newPosition[0];
182 | this._previousPosition[1]=newPosition[1];
183 | this._previousPosition[2]=newPosition[2];
184 | }
185 |
186 | return ParticleEmitter;
187 | })()
188 |
189 |
190 | /**
191 | *ParticleSettings
类是粒子配置数据类
192 | */
193 | //class laya.particle.ParticleSetting
194 | var ParticleSetting=(function(){
195 | function ParticleSetting(){
196 | /**贴图*/
197 | this.textureName=null;
198 | /**贴图个数,默认为1可不设置*/
199 | this.textureCount=1;
200 | /**由于循环队列判断算法,最大饱和粒子数为maxPartices-1*/
201 | this.maxPartices=100;
202 | /**粒子持续时间(单位:秒)*/
203 | this.duration=1;
204 | /**如果大于0,某些粒子的持续时间会小于其他粒子,并具有随机性(单位:无)*/
205 | this.ageAddScale=0;
206 | /**粒子受发射器速度的敏感度(需在自定义发射器中编码设置)*/
207 | this.emitterVelocitySensitivity=1;
208 | /**最小开始尺寸(单位:2D像素、3D坐标)*/
209 | this.minStartSize=100;
210 | /**最大开始尺寸(单位:2D像素、3D坐标)*/
211 | this.maxStartSize=100;
212 | /**最小结束尺寸(单位:2D像素、3D坐标)*/
213 | this.minEndSize=100;
214 | /**最大结束尺寸(单位:2D像素、3D坐标)*/
215 | this.maxEndSize=100;
216 | /**最小水平速度(单位:2D像素、3D坐标)*/
217 | this.minHorizontalVelocity=0;
218 | /**最大水平速度(单位:2D像素、3D坐标)*/
219 | this.maxHorizontalVelocity=0;
220 | /**最小垂直速度(单位:2D像素、3D坐标)*/
221 | this.minVerticalVelocity=0;
222 | /**最大垂直速度(单位:2D像素、3D坐标)*/
223 | this.maxVerticalVelocity=0;
224 | /**等于1时粒子从出生到消亡保持一致的速度,等于0时粒子消亡时速度为0,大于1时粒子会保持加速(单位:无)*/
225 | this.endVelocity=1;
226 | /**最小旋转速度(单位:2D弧度/秒、3D弧度/秒)*/
227 | this.minRotateSpeed=0;
228 | /**最大旋转速度(单位:2D弧度/秒、3D弧度/秒)*/
229 | this.maxRotateSpeed=0;
230 | /**最小开始半径(单位:2D像素、3D坐标)*/
231 | this.minStartRadius=0;
232 | /**最大开始半径(单位:2D像素、3D坐标)*/
233 | this.maxStartRadius=0;
234 | /**最小结束半径(单位:2D像素、3D坐标)*/
235 | this.minEndRadius=0;
236 | /**最大结束半径(单位:2D像素、3D坐标)*/
237 | this.maxEndRadius=0;
238 | /**最小水平开始弧度(单位:2D弧度、3D弧度)*/
239 | this.minHorizontalStartRadian=0;
240 | /**最大水平开始弧度(单位:2D弧度、3D弧度)*/
241 | this.maxHorizontalStartRadian=0;
242 | /**最小垂直开始弧度(单位:2D弧度、3D弧度)*/
243 | this.minVerticalStartRadian=0;
244 | /**最大垂直开始弧度(单位:2D弧度、3D弧度)*/
245 | this.maxVerticalStartRadian=0;
246 | /**是否使用结束弧度,false为结束时与起始弧度保持一致,true为根据minHorizontalEndRadian、maxHorizontalEndRadian、minVerticalEndRadian、maxVerticalEndRadian计算结束弧度。*/
247 | this.useEndRadian=true;
248 | /**最小水平结束弧度(单位:2D弧度、3D弧度)*/
249 | this.minHorizontalEndRadian=0;
250 | /**最大水平结束弧度(单位:2D弧度、3D弧度)*/
251 | this.maxHorizontalEndRadian=0;
252 | /**最小垂直结束弧度(单位:2D弧度、3D弧度)*/
253 | this.minVerticalEndRadian=0;
254 | /**最大垂直结束弧度(单位:2D弧度、3D弧度)*/
255 | this.maxVerticalEndRadian=0;
256 | /**false代表RGBA整体插值,true代表RGBA逐分量插值*/
257 | this.colorComponentInter=false;
258 | /**false代表使用参数颜色数据,true代表使用原图颜色数据*/
259 | this.disableColor=false;
260 | /**混合模式,待调整,引擎中暂无BlendState抽象*/
261 | this.blendState=0;
262 | /**发射器类型,"point","box","sphere","ring"*/
263 | this.emitterType="null";
264 | /**发射器发射速率*/
265 | this.emissionRate=0;
266 | /**球发射器半径*/
267 | this.sphereEmitterRadius=1;
268 | /**球发射器速度*/
269 | this.sphereEmitterVelocity=0;
270 | /**球发射器速度随机值*/
271 | this.sphereEmitterVelocityAddVariance=0;
272 | /**环发射器半径*/
273 | this.ringEmitterRadius=30;
274 | /**环发射器速度*/
275 | this.ringEmitterVelocity=0;
276 | /**环发射器速度随机值*/
277 | this.ringEmitterVelocityAddVariance=0;
278 | /**环发射器up向量,0代表X轴,1代表Y轴,2代表Z轴*/
279 | this.ringEmitterUp=2;
280 | this.gravity=new Float32Array([0,0,0]);
281 | this.minStartColor=new Float32Array([1,1,1,1]);
282 | this.maxStartColor=new Float32Array([1,1,1,1]);
283 | this.minEndColor=new Float32Array([1,1,1,1]);
284 | this.maxEndColor=new Float32Array([1,1,1,1]);
285 | this.pointEmitterPosition=new Float32Array([0,0,0]);
286 | this.pointEmitterPositionVariance=new Float32Array([0,0,0]);
287 | this.pointEmitterVelocity=new Float32Array([0,0,0]);
288 | this.pointEmitterVelocityAddVariance=new Float32Array([0,0,0]);
289 | this.boxEmitterCenterPosition=new Float32Array([0,0,0]);
290 | this.boxEmitterSize=new Float32Array([0,0,0]);
291 | this.boxEmitterVelocity=new Float32Array([0,0,0]);
292 | this.boxEmitterVelocityAddVariance=new Float32Array([0,0,0]);
293 | this.sphereEmitterCenterPosition=new Float32Array([0,0,0]);
294 | this.ringEmitterCenterPosition=new Float32Array([0,0,0]);
295 | this.positionVariance=new Float32Array([0,0,0]);
296 | }
297 |
298 | __class(ParticleSetting,'laya.particle.ParticleSetting');
299 | ParticleSetting.checkSetting=function(setting){
300 | var key;
301 | for (key in ParticleSetting._defaultSetting){
302 | if (!setting.hasOwnProperty(key)){
303 | setting[key]=ParticleSetting._defaultSetting[key];
304 | }
305 | }
306 | setting.endVelocity=+setting.endVelocity;
307 | setting.gravity[0]=+setting.gravity[0];
308 | setting.gravity[1]=+setting.gravity[1];
309 | setting.gravity[2]=+setting.gravity[2];
310 | }
311 |
312 | __static(ParticleSetting,
313 | ['_defaultSetting',function(){return this._defaultSetting=new ParticleSetting();}
314 | ]);
315 | return ParticleSetting;
316 | })()
317 |
318 |
319 | /**
320 | *@private
321 | */
322 | //class laya.particle.ParticleData
323 | var ParticleData=(function(){
324 | function ParticleData(){
325 | this.position=null;
326 | this.velocity=null;
327 | this.startColor=null;
328 | this.endColor=null;
329 | this.sizeRotation=null;
330 | this.radius=null;
331 | this.radian=null;
332 | this.durationAddScale=NaN;
333 | this.time=NaN;
334 | }
335 |
336 | __class(ParticleData,'laya.particle.ParticleData');
337 | ParticleData.Create=function(settings,position,velocity,time){
338 | var particleData=new ParticleData();
339 | particleData.position=position;
340 | MathUtil.scaleVector3(velocity,settings.emitterVelocitySensitivity,ParticleData._tempVelocity);
341 | var horizontalVelocity=MathUtil.lerp(settings.minHorizontalVelocity,settings.maxHorizontalVelocity,Math.random());
342 | var horizontalAngle=Math.random()*Math.PI *2;
343 | ParticleData._tempVelocity[0]+=horizontalVelocity *Math.cos(horizontalAngle);
344 | ParticleData._tempVelocity[2]+=horizontalVelocity *Math.sin(horizontalAngle);
345 | ParticleData._tempVelocity[1]+=MathUtil.lerp(settings.minVerticalVelocity,settings.maxVerticalVelocity,Math.random());
346 | particleData.velocity=ParticleData._tempVelocity;
347 | particleData.startColor=ParticleData._tempStartColor;
348 | particleData.endColor=ParticleData._tempEndColor;
349 | var i=0;
350 | if (settings.disableColor){
351 | for (i=0;i < 3;i++){
352 | particleData.startColor[i]=1;
353 | particleData.endColor[i]=1;
354 | }
355 | particleData.startColor[i]=MathUtil.lerp(settings.minStartColor[i],settings.maxStartColor[i],Math.random());
356 | particleData.endColor[i]=MathUtil.lerp(settings.minEndColor[i],settings.maxEndColor[i],Math.random());
357 | }
358 | else{
359 | if (settings.colorComponentInter){
360 | for (i=0;i < 4;i++){
361 | particleData.startColor[i]=MathUtil.lerp(settings.minStartColor[i],settings.maxStartColor[i],Math.random());
362 | particleData.endColor[i]=MathUtil.lerp(settings.minEndColor[i],settings.maxEndColor[i],Math.random());
363 | }
364 | }else {
365 | MathUtil.lerpVector4(settings.minStartColor,settings.maxStartColor,Math.random(),particleData.startColor);
366 | MathUtil.lerpVector4(settings.minEndColor,settings.maxEndColor,Math.random(),particleData.endColor);
367 | }
368 | }
369 | particleData.sizeRotation=ParticleData._tempSizeRotation;
370 | var sizeRandom=Math.random();
371 | particleData.sizeRotation[0]=MathUtil.lerp(settings.minStartSize,settings.maxStartSize,sizeRandom);
372 | particleData.sizeRotation[1]=MathUtil.lerp(settings.minEndSize,settings.maxEndSize,sizeRandom);
373 | particleData.sizeRotation[2]=MathUtil.lerp(settings.minRotateSpeed,settings.maxRotateSpeed,Math.random());
374 | particleData.radius=ParticleData._tempRadius;
375 | var radiusRandom=Math.random();
376 | particleData.radius[0]=MathUtil.lerp(settings.minStartRadius,settings.maxStartRadius,radiusRandom);
377 | particleData.radius[1]=MathUtil.lerp(settings.minEndRadius,settings.maxEndRadius,radiusRandom);
378 | particleData.radian=ParticleData._tempRadian;
379 | particleData.radian[0]=MathUtil.lerp(settings.minHorizontalStartRadian,settings.maxHorizontalStartRadian,Math.random());
380 | particleData.radian[1]=MathUtil.lerp(settings.minVerticalStartRadian,settings.maxVerticalStartRadian,Math.random());
381 | var useEndRadian=settings.useEndRadian;
382 | particleData.radian[2]=useEndRadian?MathUtil.lerp(settings.minHorizontalEndRadian,settings.maxHorizontalEndRadian,Math.random()):particleData.radian[0];
383 | particleData.radian[3]=useEndRadian?MathUtil.lerp(settings.minVerticalEndRadian,settings.maxVerticalEndRadian,Math.random()):particleData.radian[1];
384 | particleData.durationAddScale=settings.ageAddScale *Math.random();
385 | particleData.time=time;
386 | return particleData;
387 | }
388 |
389 | __static(ParticleData,
390 | ['_tempVelocity',function(){return this._tempVelocity=new Float32Array(3);},'_tempStartColor',function(){return this._tempStartColor=new Float32Array(4);},'_tempEndColor',function(){return this._tempEndColor=new Float32Array(4);},'_tempSizeRotation',function(){return this._tempSizeRotation=new Float32Array(3);},'_tempRadius',function(){return this._tempRadius=new Float32Array(2);},'_tempRadian',function(){return this._tempRadian=new Float32Array(4);}
391 | ]);
392 | return ParticleData;
393 | })()
394 |
395 |
396 | /**
397 | *@private
398 | */
399 | //class laya.particle.shader.value.ParticleShaderValue extends laya.webgl.shader.d2.value.Value2D
400 | var ParticleShaderValue=(function(_super){
401 | function ParticleShaderValue(){
402 | /*
403 | public var a_CornerTextureCoordinate:Array=[4,WebGLContext.FLOAT,false,116,0];
404 | public var a_Position:Array=[3,WebGLContext.FLOAT,false,116,16];
405 | public var a_Velocity:Array=[3,WebGLContext.FLOAT,false,116,28];
406 | public var a_StartColor:Array=[4,WebGLContext.FLOAT,false,116,40];
407 | public var a_EndColor:Array=[4,WebGLContext.FLOAT,false,116,56];
408 | public var a_SizeRotation:Array=[3,WebGLContext.FLOAT,false,116,72];
409 | public var a_Radius:Array=[2,WebGLContext.FLOAT,false,116,84];
410 | public var a_Radian:Array=[4,WebGLContext.FLOAT,false,116,92];
411 | public var a_AgeAddScale:Array=[1,WebGLContext.FLOAT,false,116,108];
412 | public var a_Time:Array=[1,WebGLContext.FLOAT,false,116,112];
413 | */
414 | this.u_CurrentTime=NaN;
415 | this.u_Duration=NaN;
416 | this.u_Gravity=null;
417 | //v3
418 | this.u_EndVelocity=NaN;
419 | this.u_texture=null;
420 | ParticleShaderValue.__super.call(this,0,0);
421 | }
422 |
423 | __class(ParticleShaderValue,'laya.particle.shader.value.ParticleShaderValue',_super);
424 | var __proto=ParticleShaderValue.prototype;
425 | /*�ŵ� ParticleShader ����
426 | this._attribLocation=['a_CornerTextureCoordinate',0,'a_Position',1,'a_Velocity',2,'a_StartColor',3,
427 | 'a_EndColor',4,'a_SizeRotation',5,'a_Radius',6,'a_Radian',7,'a_AgeAddScale',8,'a_Time',9];
428 | */
429 | __proto.upload=function(){
430 | var size=this.size;
431 | size[0]=RenderState2D.width;
432 | size[1]=RenderState2D.height;
433 | this.alpha=this.ALPHA *RenderState2D.worldAlpha;
434 | ParticleShaderValue.pShader.upload(this);
435 | }
436 |
437 | __static(ParticleShaderValue,
438 | ['pShader',function(){return this.pShader=new ParticleShader();}
439 | ]);
440 | return ParticleShaderValue;
441 | })(Value2D)
442 |
443 |
444 | /**
445 | *@private
446 | */
447 | //class laya.particle.ParticleTemplateWebGL extends laya.particle.ParticleTemplateBase
448 | var ParticleTemplateWebGL=(function(_super){
449 | function ParticleTemplateWebGL(parSetting){
450 | this._vertices=null;
451 | //protected var _indexBuffer:Buffer;
452 | this._mesh=null;
453 | this._conchMesh=null;
454 | this._floatCountPerVertex=29;
455 | //0~3为CornerTextureCoordinate,4~6为Position,7~9Velocity,10到13为StartColor,14到17为EndColor,18到20位SizeRotation,21到22位Radius,23到26位Radian,27为DurationAddScaleShaderValue,28为Time
456 | this._firstActiveElement=0;
457 | this._firstNewElement=0;
458 | this._firstFreeElement=0;
459 | this._firstRetiredElement=0;
460 | this._currentTime=0;
461 | this._drawCounter=0;
462 | ParticleTemplateWebGL.__super.call(this);
463 | this.settings=parSetting;
464 | }
465 |
466 | __class(ParticleTemplateWebGL,'laya.particle.ParticleTemplateWebGL',_super);
467 | var __proto=ParticleTemplateWebGL.prototype;
468 | __proto.reUse=function(context,pos){
469 | return 0;
470 | }
471 |
472 | __proto.initialize=function(){
473 | var floatStride=0;
474 | this._vertices=this._mesh._vb.getFloat32Array();
475 | floatStride=this._mesh._stride / 4;
476 | var bufi=0;
477 | var bufStart=0;
478 | for (var i=0;i < this.settings.maxPartices;i++){
479 | var random=Math.random();
480 | var cornerYSegement=this.settings.textureCount ? 1.0 / this.settings.textureCount :1.0;
481 | var cornerY=NaN;
482 | for (cornerY=0;cornerY < this.settings.textureCount;cornerY+=cornerYSegement){
483 | if (random < cornerY+cornerYSegement)
484 | break ;
485 | }
486 | this._vertices[bufi++]=-1;
487 | this._vertices[bufi++]=-1;
488 | this._vertices[bufi++]=0;
489 | this._vertices[bufi++]=cornerY;
490 | bufi=(bufStart+=floatStride);
491 | this._vertices[bufi++]=1;
492 | this._vertices[bufi++]=-1;
493 | this._vertices[bufi++]=1;
494 | this._vertices[bufi++]=cornerY;
495 | bufi=bufStart+=floatStride;
496 | this._vertices[bufi++]=1;
497 | this._vertices[bufi++]=1;
498 | this._vertices[bufi++]=1;
499 | this._vertices[bufi++]=cornerY+cornerYSegement;
500 | bufi=bufStart+=floatStride;
501 | this._vertices[bufi++]=-1;
502 | this._vertices[bufi++]=1;
503 | this._vertices[bufi++]=0;
504 | this._vertices[bufi++]=cornerY+cornerYSegement;
505 | bufi=bufStart+=floatStride;
506 | }
507 | }
508 |
509 | __proto.update=function(elapsedTime){
510 | this._currentTime+=elapsedTime / 1000;
511 | this.retireActiveParticles();
512 | this.freeRetiredParticles();
513 | if (this._firstActiveElement==this._firstFreeElement)
514 | this._currentTime=0;
515 | if (this._firstRetiredElement==this._firstActiveElement)
516 | this._drawCounter=0;
517 | }
518 |
519 | __proto.retireActiveParticles=function(){
520 | var epsilon=0.0001;
521 | var particleDuration=this.settings.duration;
522 | while (this._firstActiveElement !=this._firstNewElement){
523 | var offset=this._firstActiveElement *this._floatCountPerVertex *4;
524 | var index=offset+28;
525 | var particleAge=this._currentTime-this._vertices[index];
526 | particleAge *=(1.0+this._vertices[offset+27]);
527 | if (particleAge+epsilon < particleDuration)
528 | break ;
529 | this._vertices[index]=this._drawCounter;
530 | this._firstActiveElement++;
531 | if (this._firstActiveElement >=this.settings.maxPartices)
532 | this._firstActiveElement=0;
533 | }
534 | }
535 |
536 | __proto.freeRetiredParticles=function(){
537 | while (this._firstRetiredElement !=this._firstActiveElement){
538 | var age=this._drawCounter-this._vertices[this._firstRetiredElement *this._floatCountPerVertex *4+28];
539 | if (age < 3)
540 | break ;
541 | this._firstRetiredElement++;
542 | if (this._firstRetiredElement >=this.settings.maxPartices)
543 | this._firstRetiredElement=0;
544 | }
545 | }
546 |
547 | __proto.addNewParticlesToVertexBuffer=function(){}
548 | //由于循环队列判断算法,当下一个freeParticle等于retiredParticle时不添加例子,意味循环队列中永远有一个空位。(由于此判断算法快速、简单,所以放弃了使循环队列饱和的复杂算法(需判断freeParticle在retiredParticle前、后两种情况并不同处理))
549 | __proto.addParticleArray=function(position,velocity){
550 | var nextFreeParticle=this._firstFreeElement+1;
551 | if (nextFreeParticle >=this.settings.maxPartices)
552 | nextFreeParticle=0;
553 | if (nextFreeParticle===this._firstRetiredElement)
554 | return;
555 | var particleData=ParticleData.Create(this.settings,position,velocity,this._currentTime);
556 | var startIndex=this._firstFreeElement *this._floatCountPerVertex *4;
557 | for (var i=0;i < 4;i++){
558 | var j=0,offset=0;
559 | for (j=0,offset=4;j < 3;j++)
560 | this._vertices[startIndex+i *this._floatCountPerVertex+offset+j]=particleData.position[j];
561 | for (j=0,offset=7;j < 3;j++)
562 | this._vertices[startIndex+i *this._floatCountPerVertex+offset+j]=particleData.velocity[j];
563 | for (j=0,offset=10;j < 4;j++)
564 | this._vertices[startIndex+i *this._floatCountPerVertex+offset+j]=particleData.startColor[j];
565 | for (j=0,offset=14;j < 4;j++)
566 | this._vertices[startIndex+i *this._floatCountPerVertex+offset+j]=particleData.endColor[j];
567 | for (j=0,offset=18;j < 3;j++)
568 | this._vertices[startIndex+i *this._floatCountPerVertex+offset+j]=particleData.sizeRotation[j];
569 | for (j=0,offset=21;j < 2;j++)
570 | this._vertices[startIndex+i *this._floatCountPerVertex+offset+j]=particleData.radius[j];
571 | for (j=0,offset=23;j < 4;j++)
572 | this._vertices[startIndex+i *this._floatCountPerVertex+offset+j]=particleData.radian[j];
573 | this._vertices[startIndex+i *this._floatCountPerVertex+27]=particleData.durationAddScale;
574 | this._vertices[startIndex+i *this._floatCountPerVertex+28]=particleData.time;
575 | }
576 | this._firstFreeElement=nextFreeParticle;
577 | }
578 |
579 | return ParticleTemplateWebGL;
580 | })(ParticleTemplateBase)
581 |
582 |
583 | /**
584 | *
585 | *@private
586 | */
587 | //class laya.particle.emitter.Emitter2D extends laya.particle.emitter.EmitterBase
588 | var Emitter2D=(function(_super){
589 | function Emitter2D(_template){
590 | this.setting=null;
591 | this._posRange=null;
592 | this._canvasTemplate=null;
593 | this._emitFun=null;
594 | Emitter2D.__super.call(this);
595 | this.template=_template;
596 | }
597 |
598 | __class(Emitter2D,'laya.particle.emitter.Emitter2D',_super);
599 | var __proto=Emitter2D.prototype;
600 | __proto.emit=function(){
601 | _super.prototype.emit.call(this);
602 | if(this._emitFun!=null)
603 | this._emitFun();
604 | }
605 |
606 | __proto.getRandom=function(value){
607 | return (Math.random()*2-1)*value;
608 | }
609 |
610 | __proto.webGLEmit=function(){
611 | var pos=new Float32Array(3);
612 | pos[0]=this.getRandom(this._posRange[0]);
613 | pos[1]=this.getRandom(this._posRange[1]);
614 | pos[2]=this.getRandom(this._posRange[2]);
615 | var v=new Float32Array(3);
616 | v[0]=0;
617 | v[1]=0;
618 | v[2]=0;
619 | this._particleTemplate.addParticleArray(pos,v);
620 | }
621 |
622 | __proto.canvasEmit=function(){
623 | var pos=new Float32Array(3);
624 | pos[0]=this.getRandom(this._posRange[0]);
625 | pos[1]=this.getRandom(this._posRange[1]);
626 | pos[2]=this.getRandom(this._posRange[2]);
627 | var v=new Float32Array(3);
628 | v[0]=0;
629 | v[1]=0;
630 | v[2]=0;
631 | this._particleTemplate.addParticleArray(pos,v);
632 | }
633 |
634 | __getset(0,__proto,'template',function(){
635 | return this._particleTemplate;
636 | },function(template){
637 | this._particleTemplate=template;
638 | if (!template){
639 | this._emitFun=null;
640 | this.setting=null;
641 | this._posRange=null;
642 | };
643 | this.setting=template.settings;
644 | this._posRange=this.setting.positionVariance;
645 | if((this._particleTemplate instanceof laya.particle.ParticleTemplate2D )){
646 | this._emitFun=this.webGLEmit;
647 | }
648 | });
649 |
650 | return Emitter2D;
651 | })(EmitterBase)
652 |
653 |
654 | /**
655 | *@private
656 | */
657 | //class laya.particle.ParticleTemplate2D extends laya.particle.ParticleTemplateWebGL
658 | var ParticleTemplate2D=(function(_super){
659 | function ParticleTemplate2D(parSetting){
660 | this.x=0;
661 | this.y=0;
662 | this._blendFn=null;
663 | this._startTime=0;
664 | this._key={};
665 | this.sv=new ParticleShaderValue();
666 | ParticleTemplate2D.__super.call(this,parSetting);
667 | var _this=this;
668 | Laya.loader.load(this.settings.textureName,Handler.create(null,function(texture){
669 | _this.texture=texture;
670 | }));
671 | this.sv.u_Duration=this.settings.duration;
672 | this.sv.u_Gravity=this.settings.gravity;
673 | this.sv.u_EndVelocity=this.settings.endVelocity;
674 | this._blendFn=BlendMode.fns[parSetting.blendState];
675 | this._mesh=MeshParticle2D.getAMesh(this.settings.maxPartices);
676 | this.initialize();
677 | }
678 |
679 | __class(ParticleTemplate2D,'laya.particle.ParticleTemplate2D',_super);
680 | var __proto=ParticleTemplate2D.prototype;
681 | Laya.imps(__proto,{"laya.webgl.submit.ISubmit":true})
682 | //loadContent();
683 | __proto.getRenderType=function(){return-111}
684 | __proto.releaseRender=function(){}
685 | __proto.addParticleArray=function(position,velocity){
686 | position[0]+=this.x;
687 | position[1]+=this.y;
688 | _super.prototype.addParticleArray.call(this,position,velocity);
689 | }
690 |
691 | /*
692 | override protected function loadContent():void{
693 | var indexes:Uint16Array=new Uint16Array(settings.maxPartices *6);
694 | for (var i:int=0;i < settings.maxPartices;i++){
695 | indexes[i *6+0]=(i *4+0);
696 | indexes[i *6+1]=(i *4+1);
697 | indexes[i *6+2]=(i *4+2);
698 | indexes[i *6+3]=(i *4+0);
699 | indexes[i *6+4]=(i *4+2);
700 | indexes[i *6+5]=(i *4+3);
701 | }
702 | _indexBuffer2D.clear();
703 | _indexBuffer2D.append(indexes);
704 | _indexBuffer2D.upload();
705 | }
706 |
707 | */
708 | __proto.addNewParticlesToVertexBuffer=function(){
709 | var _vertexBuffer2D=this._mesh._vb;
710 | _vertexBuffer2D.clear();
711 | _vertexBuffer2D.append(this._vertices);
712 | var start=0;
713 | if (this._firstNewElement < this._firstFreeElement){
714 | start=this._firstNewElement *4 *this._floatCountPerVertex *4;
715 | _vertexBuffer2D.subUpload(start,start,start+(this._firstFreeElement-this._firstNewElement)*4 *this._floatCountPerVertex *4);
716 | }else {
717 | start=this._firstNewElement *4 *this._floatCountPerVertex *4;
718 | _vertexBuffer2D.subUpload(start,start,start+(this.settings.maxPartices-this._firstNewElement)*4 *this._floatCountPerVertex *4);
719 | if (this._firstFreeElement > 0){
720 | _vertexBuffer2D.setNeedUpload();
721 | _vertexBuffer2D.subUpload(0,0,this._firstFreeElement *4 *this._floatCountPerVertex *4);
722 | }
723 | }
724 | this._firstNewElement=this._firstFreeElement;
725 | }
726 |
727 | __proto.renderSubmit=function(){
728 | if (this.texture&&this.texture.getIsReady()){
729 | this.update(Laya.timer._delta);
730 | this.sv.u_CurrentTime=this._currentTime;
731 | if (this._firstNewElement !=this._firstFreeElement){
732 | this.addNewParticlesToVertexBuffer();
733 | }
734 | this.blend();
735 | if (this._firstActiveElement !=this._firstFreeElement){
736 | var gl=WebGL.mainContext;
737 | this._mesh.useMesh(gl);
738 | this.sv.u_texture=this.texture._getSource();
739 | this.sv.upload();
740 | if (this._firstActiveElement < this._firstFreeElement){
741 | WebGL.mainContext.drawElements(/*laya.webgl.WebGLContext.TRIANGLES*/0x0004,(this._firstFreeElement-this._firstActiveElement)*6,/*laya.webgl.WebGLContext.UNSIGNED_SHORT*/0x1403,this._firstActiveElement *6 *2);
742 | }
743 | else{
744 | WebGL.mainContext.drawElements(/*laya.webgl.WebGLContext.TRIANGLES*/0x0004,(this.settings.maxPartices-this._firstActiveElement)*6,/*laya.webgl.WebGLContext.UNSIGNED_SHORT*/0x1403,this._firstActiveElement *6 *2);
745 | if (this._firstFreeElement > 0)
746 | WebGL.mainContext.drawElements(/*laya.webgl.WebGLContext.TRIANGLES*/0x0004,this._firstFreeElement *6,/*laya.webgl.WebGLContext.UNSIGNED_SHORT*/0x1403,0);
747 | }
748 | Stat.renderBatches++;
749 | }
750 | this._drawCounter++;
751 | }
752 | return 1;
753 | }
754 |
755 | __proto.updateParticleForNative=function(){
756 | if (this.texture&&this.texture.getIsReady()){
757 | this.update(Laya.timer._delta);
758 | this.sv.u_CurrentTime=this._currentTime;
759 | if (this._firstNewElement !=this._firstFreeElement){
760 | this._firstNewElement=this._firstFreeElement;
761 | }
762 | }
763 | }
764 |
765 | __proto.getMesh=function(){
766 | return this._mesh;
767 | }
768 |
769 | __proto.getConchMesh=function(){
770 | return this._conchMesh;
771 | }
772 |
773 | __proto.getFirstNewElement=function(){
774 | return this._firstNewElement;
775 | }
776 |
777 | __proto.getFirstFreeElement=function(){
778 | return this._firstFreeElement;
779 | }
780 |
781 | __proto.getFirstActiveElement=function(){
782 | return this._firstActiveElement;
783 | }
784 |
785 | __proto.getFirstRetiredElement=function(){
786 | return this._firstRetiredElement;
787 | }
788 |
789 | __proto.setFirstFreeElement=function(_value){
790 | this._firstFreeElement=_value;
791 | }
792 |
793 | __proto.setFirstNewElement=function(_value){
794 | this._firstNewElement=_value;
795 | }
796 |
797 | __proto.addDrawCounter=function(){
798 | this._drawCounter++;
799 | }
800 |
801 | __proto.blend=function(){
802 | if (BlendMode.activeBlendFunction!==this._blendFn){
803 | var gl=WebGL.mainContext;
804 | gl.enable(/*laya.webgl.WebGLContext.BLEND*/0x0BE2);
805 | this._blendFn(gl);
806 | BlendMode.activeBlendFunction=this._blendFn;
807 | }
808 | }
809 |
810 | __proto.dispose=function(){
811 | this._mesh.releaseMesh();
812 | }
813 |
814 | ParticleTemplate2D.activeBlendType=-1;
815 | return ParticleTemplate2D;
816 | })(ParticleTemplateWebGL)
817 |
818 |
819 | /**
820 | *Particle2D
类是2D粒子播放类
821 | *
822 | */
823 | //class laya.particle.Particle2D extends laya.display.Sprite
824 | var Particle2D=(function(_super){
825 | function Particle2D(setting){
826 | /**@private */
827 | this._particleTemplate=null;
828 | /**@private */
829 | this._emitter=null;
830 | /**是否自动播放*/
831 | this.autoPlay=true;
832 | this.tempCmd=null;
833 | Particle2D.__super.call(this);
834 | this._matrix4=new Float32Array([1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1]);
835 | this.customRenderEnable=true;
836 | if (setting)this.setParticleSetting(setting);
837 | }
838 |
839 | __class(Particle2D,'laya.particle.Particle2D',_super);
840 | var __proto=Particle2D.prototype;
841 | /**
842 | *加载粒子文件
843 | *@param url 粒子文件地址
844 | */
845 | __proto.load=function(url){
846 | Laya.loader.load(url,Handler.create(this,this.setParticleSetting),null,/*laya.net.Loader.JSON*/"json");
847 | }
848 |
849 | /**
850 | *设置粒子配置数据
851 | *@param settings 粒子配置数据
852 | */
853 | __proto.setParticleSetting=function(setting){
854 | if (!setting)return this.stop();
855 | ParticleSetting.checkSetting(setting);
856 | this.customRenderEnable=true;
857 | this._particleTemplate=new ParticleTemplate2D(setting);
858 | this.graphics._saveToCmd(null,DrawParticleCmd.create(this._particleTemplate));
859 | if (!this._emitter){
860 | this._emitter=new Emitter2D(this._particleTemplate);
861 | }else {
862 | (this._emitter).template=this._particleTemplate;
863 | }
864 | if (this.autoPlay){
865 | this.emitter.start();
866 | this.play();
867 | }
868 | }
869 |
870 | /**
871 | *播放
872 | */
873 | __proto.play=function(){
874 | Laya.timer.frameLoop(1,this,this._loop);
875 | }
876 |
877 | /**
878 | *停止
879 | */
880 | __proto.stop=function(){
881 | Laya.timer.clear(this,this._loop);
882 | }
883 |
884 | /**@private */
885 | __proto._loop=function(){
886 | this.advanceTime(1 / 60);
887 | }
888 |
889 | /**
890 | *时钟前进
891 | *@param passedTime 时钟前进时间
892 | */
893 | __proto.advanceTime=function(passedTime){
894 | (passedTime===void 0)&& (passedTime=1);
895 | if (this._emitter){
896 | this._emitter.advanceTime(passedTime);
897 | }
898 | }
899 |
900 | __proto.customRender=function(context,x,y){
901 | this._matrix4[0]=context._curMat.a;
902 | this._matrix4[1]=context._curMat.b;
903 | this._matrix4[4]=context._curMat.c;
904 | this._matrix4[5]=context._curMat.d;
905 | this._matrix4[12]=context._curMat.tx;
906 | this._matrix4[13]=context._curMat.ty;
907 | var sv=(this._particleTemplate).sv;
908 | sv.u_mmat=this._matrix4;
909 | }
910 |
911 | __proto.destroy=function(destroyChild){
912 | (destroyChild===void 0)&& (destroyChild=true);
913 | if ((this._particleTemplate instanceof laya.particle.ParticleTemplate2D ))
914 | (this._particleTemplate).dispose();
915 | _super.prototype.destroy.call(this,destroyChild);
916 | }
917 |
918 | /**
919 | *设置 粒子文件地址
920 | *@param path 粒子文件地址
921 | */
922 | __getset(0,__proto,'url',null,function(url){
923 | this.load(url);
924 | });
925 |
926 | /**
927 | *获取粒子发射器
928 | */
929 | __getset(0,__proto,'emitter',function(){
930 | return this._emitter;
931 | });
932 |
933 | return Particle2D;
934 | })(Sprite)
935 |
936 |
937 | /**
938 | *@private
939 | */
940 | //class laya.particle.shader.ParticleShader extends laya.webgl.shader.Shader
941 | var ParticleShader=(function(_super){
942 | //TODO:coverage
943 | function ParticleShader(){
944 | ParticleShader.__super.call(this,ParticleShader.vs,ParticleShader.ps,"ParticleShader",null,['a_CornerTextureCoordinate',0,'a_Position',1,'a_Velocity',2,'a_StartColor',3,
945 | 'a_EndColor',4,'a_SizeRotation',5,'a_Radius',6,'a_Radian',7,'a_AgeAddScale',8,'a_Time',9]);
946 | }
947 |
948 | __class(ParticleShader,'laya.particle.shader.ParticleShader',_super);
949 | __static(ParticleShader,
950 | ['vs',function(){return this.vs="attribute vec4 a_CornerTextureCoordinate;\nattribute vec3 a_Position;\nattribute vec3 a_Velocity;\nattribute vec4 a_StartColor;\nattribute vec4 a_EndColor;\nattribute vec3 a_SizeRotation;\nattribute vec2 a_Radius;\nattribute vec4 a_Radian;\nattribute float a_AgeAddScale;\nattribute float a_Time;\n\nvarying vec4 v_Color;\nvarying vec2 v_TextureCoordinate;\n\nuniform float u_CurrentTime;\nuniform float u_Duration;\nuniform float u_EndVelocity;\nuniform vec3 u_Gravity;\n\nuniform vec2 size;\nuniform mat4 u_mmat;\n\nvec4 ComputeParticlePosition(in vec3 position, in vec3 velocity,in float age,in float normalizedAge)\n{\n\n float startVelocity = length(velocity);//起始标量速度\n float endVelocity = startVelocity * u_EndVelocity;//结束标量速度\n\n float velocityIntegral = startVelocity * normalizedAge +(endVelocity - startVelocity) * normalizedAge *normalizedAge/2.0;//计算当前速度的标量(单位空间),vt=v0*t+(1/2)*a*(t^2)\n \n vec3 addPosition = normalize(velocity) * velocityIntegral * u_Duration;//计算受自身速度影响的位置,转换标量到矢量 \n addPosition += u_Gravity * age * normalizedAge;//计算受重力影响的位置\n \n float radius=mix(a_Radius.x, a_Radius.y, normalizedAge); //计算粒子受半径和角度影响(无需计算角度和半径时,可用宏定义优化屏蔽此计算)\n float radianHorizontal =mix(a_Radian.x,a_Radian.z,normalizedAge);\n float radianVertical =mix(a_Radian.y,a_Radian.w,normalizedAge);\n \n float r =cos(radianVertical)* radius;\n addPosition.y += sin(radianVertical) * radius;\n \n addPosition.x += cos(radianHorizontal) *r;\n addPosition.z += sin(radianHorizontal) *r;\n \n addPosition.y=-addPosition.y;//2D粒子位置更新需要取负,2D粒子坐标系Y轴正向朝上\n position+=addPosition;\n return vec4(position,1.0);\n}\n\nfloat ComputeParticleSize(in float startSize,in float endSize, in float normalizedAge)\n{ \n float size = mix(startSize, endSize, normalizedAge);\n return size;\n}\n\nmat2 ComputeParticleRotation(in float rot,in float age)\n{ \n float rotation =rot * age;\n //计算2x2旋转矩阵.\n float c = cos(rotation);\n float s = sin(rotation);\n return mat2(c, -s, s, c);\n}\n\nvec4 ComputeParticleColor(in vec4 startColor,in vec4 endColor,in float normalizedAge)\n{\n vec4 color=mix(startColor,endColor,normalizedAge);\n //硬编码设置,使粒子淡入很快,淡出很慢,6.7的缩放因子把置归一在0到1之间,可以谷歌x*(1-x)*(1-x)*6.7的制图表\n color.a *= normalizedAge * (1.0-normalizedAge) * (1.0-normalizedAge) * 6.7;\n \n return color;\n}\n\nvoid main()\n{\n float age = u_CurrentTime - a_Time;\n age *= 1.0 + a_AgeAddScale;\n float normalizedAge = clamp(age / u_Duration,0.0,1.0);\n gl_Position = ComputeParticlePosition(a_Position, a_Velocity, age, normalizedAge);//计算粒子位置\n float pSize = ComputeParticleSize(a_SizeRotation.x,a_SizeRotation.y, normalizedAge);\n mat2 rotation = ComputeParticleRotation(a_SizeRotation.z, age);\n \n mat4 mat=u_mmat;\n gl_Position=vec4((mat*gl_Position).xy,0.0,1.0);\n gl_Position.xy += (rotation*a_CornerTextureCoordinate.xy) * pSize*vec2(mat[0][0],mat[1][1]);\n gl_Position=vec4((gl_Position.x/size.x-0.5)*2.0,(0.5-gl_Position.y/size.y)*2.0,0.0,1.0);\n \n v_Color = ComputeParticleColor(a_StartColor,a_EndColor, normalizedAge);\n v_TextureCoordinate =a_CornerTextureCoordinate.zw;\n}\n\n";},'ps',function(){return this.ps="#ifdef FSHIGHPRECISION\nprecision highp float;\n#else\nprecision mediump float;\n#endif\n\nvarying vec4 v_Color;\nvarying vec2 v_TextureCoordinate;\nuniform sampler2D u_texture;\n\nvoid main()\n{ \n gl_FragColor=texture2D(u_texture,v_TextureCoordinate)*v_Color;\n gl_FragColor.xyz *= v_Color.w;\n}";}
951 | ]);
952 | return ParticleShader;
953 | })(Shader)
954 |
955 |
956 |
957 | })(window,document,Laya);
958 |
--------------------------------------------------------------------------------
/bin/libs/laya.physics3D.wasm.wasm:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lizenghua/JoyStick/f6b04af496d90c5a15b5f17223ad85c2f9234418/bin/libs/laya.physics3D.wasm.wasm
--------------------------------------------------------------------------------
/bin/libs/worker.js:
--------------------------------------------------------------------------------
1 | function testCanImageData(){try{cc=new ImageData(20,20),canUseImageData=!0}catch(t){}}function loadImage(t){PNG.load(t.url,pngLoaded)}function loadImage2(t){var e,a=t.url;e=new XMLHttpRequest,e.open("GET",a,!0),e.responseType="arraybuffer",e.onload=function(){var t,i,r=e.response||e.mozResponseArrayBuffer;if(t=new Uint8Array(r),self.createImageBitmap)return void doCreateImageBitmap(t,a);try{startTime=getTimeNow(),i=new PNG(t),i.url=a,i.startTime=startTime,i.decodeEndTime=getTimeNow(),i.decodeTime=i.decodeEndTime-startTime,pngLoaded(i)}catch(s){pngFail(a,"parse fail"+s.toString()+":ya")}},e.onerror=function(t){pngFail(a,"loadFail")},e.send(null)}function doCreateImageBitmap(t,e){try{var a=getTimeNow();t=new self.Blob([t],{type:"image/png"}),self.createImageBitmap(t).then(function(t){var i={};i.url=e,i.imageBitmap=t,i.dataType="imageBitmap",i.startTime=a,i.decodeTime=getTimeNow()-a,i.sendTime=getTimeNow(),console.log("Decode By createImageBitmap,"+i.decodeTime,e),i.type="Image",postMessage(i,[i.imageBitmap])})["catch"](function(t){showMsgToMain("cache:"+t),pngFail(e,"parse fail"+t+":ya")})}catch(i){pngFail(e,"parse fail"+i.toString()+":ya")}}function getTimeNow(){return(new Date).getTime()}function pngFail(t,e){var a={};a.url=t,a.imagedata=null,a.type="Image",a.msg=e,console.log(e),postMessage(a)}function showMsgToMain(t){var e={};e.type="Msg",e.msg=t,postMessage(e)}function pngLoaded(t){var e={};e.url=t.url,canUseImageData?(e.imagedata=t.getImageData(),e.dataType="imagedata"):(e.buffer=t.getImageDataBuffer(),e.dataType="buffer"),e.width=t.width,e.height=t.height,e.decodeTime=getTimeNow()-t.startTime,console.log("Decode By PNG.js,"+(getTimeNow()-t.startTime),t.url),e.type="Image",canUseImageData?postMessage(e,[e.imagedata.data.buffer]):postMessage(e,[e.buffer.buffer])}var DecodeStream=function(){function t(){this.pos=0,this.bufferLength=0,this.eof=!1,this.buffer=null}return t.prototype={ensureBuffer:function(t){var e=this.buffer,a=e?e.byteLength:0;if(a>t)return e;for(var i=512;t>i;)i<<=1;for(var r=new Uint8Array(i),s=0;a>s;++s)r[s]=e[s];return this.buffer=r},getByte:function(){for(var t=this.pos;this.bufferLength<=t;){if(this.eof)return null;this.readBlock()}return this.buffer[this.pos++]},getBytes:function(t){var e=this.pos;if(t){this.ensureBuffer(e+t);for(var a=e+t;!this.eof&&this.bufferLengthi&&(a=i)}else{for(;!this.eof;)this.readBlock();var a=this.bufferLength}return this.pos=a,this.buffer.subarray(e,a)},lookChar:function(){for(var t=this.pos;this.bufferLength<=t;){if(this.eof)return null;this.readBlock()}return String.fromCharCode(this.buffer[this.pos])},getChar:function(){for(var t=this.pos;this.bufferLength<=t;){if(this.eof)return null;this.readBlock()}return String.fromCharCode(this.buffer[this.pos++])},makeSubStream:function(t,e,a){for(var i=t+e;this.bufferLength<=i&&!this.eof;)this.readBlock();return new Stream(this.buffer,t,e,a)},skip:function(t){t||(t=1),this.pos+=t},reset:function(){this.pos=0}},t}(),FlateStream=function(){function t(t){throw new Error(t)}function e(e){var a=0,i=e[a++],r=e[a++];-1!=i&&-1!=r||t("Invalid header in flate stream"),8!=(15&i)&&t("Unknown compression method in flate stream"),((i<<8)+r)%31!=0&&t("Bad FCHECK in flate stream"),32&r&&t("FDICT bit set in flate stream"),this.bytes=e,this.bytesPos=a,this.codeSize=0,this.codeBuf=0,DecodeStream.call(this)}var a=new Uint32Array([16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15]),i=new Uint32Array([3,4,5,6,7,8,9,10,65547,65549,65551,65553,131091,131095,131099,131103,196643,196651,196659,196667,262211,262227,262243,262259,327811,327843,327875,327907,258,258,258]),r=new Uint32Array([1,2,3,4,65541,65543,131081,131085,196625,196633,262177,262193,327745,327777,393345,393409,459009,459137,524801,525057,590849,591361,657409,658433,724993,727041,794625,798721,868353,876545]),s=[new Uint32Array([459008,524368,524304,524568,459024,524400,524336,590016,459016,524384,524320,589984,524288,524416,524352,590048,459012,524376,524312,589968,459028,524408,524344,590032,459020,524392,524328,59e4,524296,524424,524360,590064,459010,524372,524308,524572,459026,524404,524340,590024,459018,524388,524324,589992,524292,524420,524356,590056,459014,524380,524316,589976,459030,524412,524348,590040,459022,524396,524332,590008,524300,524428,524364,590072,459009,524370,524306,524570,459025,524402,524338,590020,459017,524386,524322,589988,524290,524418,524354,590052,459013,524378,524314,589972,459029,524410,524346,590036,459021,524394,524330,590004,524298,524426,524362,590068,459011,524374,524310,524574,459027,524406,524342,590028,459019,524390,524326,589996,524294,524422,524358,590060,459015,524382,524318,589980,459031,524414,524350,590044,459023,524398,524334,590012,524302,524430,524366,590076,459008,524369,524305,524569,459024,524401,524337,590018,459016,524385,524321,589986,524289,524417,524353,590050,459012,524377,524313,589970,459028,524409,524345,590034,459020,524393,524329,590002,524297,524425,524361,590066,459010,524373,524309,524573,459026,524405,524341,590026,459018,524389,524325,589994,524293,524421,524357,590058,459014,524381,524317,589978,459030,524413,524349,590042,459022,524397,524333,590010,524301,524429,524365,590074,459009,524371,524307,524571,459025,524403,524339,590022,459017,524387,524323,589990,524291,524419,524355,590054,459013,524379,524315,589974,459029,524411,524347,590038,459021,524395,524331,590006,524299,524427,524363,590070,459011,524375,524311,524575,459027,524407,524343,590030,459019,524391,524327,589998,524295,524423,524359,590062,459015,524383,524319,589982,459031,524415,524351,590046,459023,524399,524335,590014,524303,524431,524367,590078,459008,524368,524304,524568,459024,524400,524336,590017,459016,524384,524320,589985,524288,524416,524352,590049,459012,524376,524312,589969,459028,524408,524344,590033,459020,524392,524328,590001,524296,524424,524360,590065,459010,524372,524308,524572,459026,524404,524340,590025,459018,524388,524324,589993,524292,524420,524356,590057,459014,524380,524316,589977,459030,524412,524348,590041,459022,524396,524332,590009,524300,524428,524364,590073,459009,524370,524306,524570,459025,524402,524338,590021,459017,524386,524322,589989,524290,524418,524354,590053,459013,524378,524314,589973,459029,524410,524346,590037,459021,524394,524330,590005,524298,524426,524362,590069,459011,524374,524310,524574,459027,524406,524342,590029,459019,524390,524326,589997,524294,524422,524358,590061,459015,524382,524318,589981,459031,524414,524350,590045,459023,524398,524334,590013,524302,524430,524366,590077,459008,524369,524305,524569,459024,524401,524337,590019,459016,524385,524321,589987,524289,524417,524353,590051,459012,524377,524313,589971,459028,524409,524345,590035,459020,524393,524329,590003,524297,524425,524361,590067,459010,524373,524309,524573,459026,524405,524341,590027,459018,524389,524325,589995,524293,524421,524357,590059,459014,524381,524317,589979,459030,524413,524349,590043,459022,524397,524333,590011,524301,524429,524365,590075,459009,524371,524307,524571,459025,524403,524339,590023,459017,524387,524323,589991,524291,524419,524355,590055,459013,524379,524315,589975,459029,524411,524347,590039,459021,524395,524331,590007,524299,524427,524363,590071,459011,524375,524311,524575,459027,524407,524343,590031,459019,524391,524327,589999,524295,524423,524359,590063,459015,524383,524319,589983,459031,524415,524351,590047,459023,524399,524335,590015,524303,524431,524367,590079]),9],n=[new Uint32Array([327680,327696,327688,327704,327684,327700,327692,327708,327682,327698,327690,327706,327686,327702,327694,0,327681,327697,327689,327705,327685,327701,327693,327709,327683,327699,327691,327707,327687,327703,327695,0]),5];return e.prototype=Object.create(DecodeStream.prototype),e.prototype.getBits=function(e){for(var a,i=this.codeSize,r=this.codeBuf,s=this.bytes,n=this.bytesPos;e>i;)"undefined"==typeof(a=s[n++])&&t("Bad encoding in flate stream"),r|=a<>e,this.codeSize=i-=e,this.bytesPos=n,a},e.prototype.getCode=function(e){for(var a=e[0],i=e[1],r=this.codeSize,s=this.codeBuf,n=this.bytes,o=this.bytesPos;i>r;){var h;"undefined"==typeof(h=n[o++])&&t("Bad encoding in flate stream"),s|=h<