一、微信相关功能扩展与说明
- 微信授权:最近项目中遇到一个需求,那就是需要获取到玩家的头像昵称,然后上传给服务器,留作以后排行榜和玩家详情时显示,需要当游戏进行到某一个环节,比如新手引导结束或者进入大厅时,玩家点击某个地方弹出授权弹窗,于是便有了如下创建全屏透明微信授权button的代码。
// 创建全屏透明文本授权按钮 let systemInfo = window['wx'].getSystemInfoSync(); let wxButton = window['wx'].createUserInfoButton({ type: 'text', text: '', style: { left: 0, top: 0, width: systemInfo.screenWidth, height: systemInfo.screenHeight, lineHeight: 40, textAlign: 'center', } }); wxButton.onTap((res) => { if (res.errMsg.indexOf('auth deny') > -1 || res.errMsg.indexOf('auth denied') > -1) { cc.log('用户拒绝授权'); wxButton.destroy(); } else { cc.log('授权成功:', JSON.stringify(res)); wxButton.destroy(); // setUserData let player: Player = Game.getInstance().player; player.setNick(res.userInfo.nickName); player.setAvatar(res.userInfo.avatarUrl); player.setGender(res.userInfo.gender); cc.log('player.attr:', JSON.stringify(player.attr)); // this.sendSetPlayerInfoReq(); // Game.getInstance().gNode.emit(EventConfig.EVT_WX_REFRESH_PLAYER_INFO); } });
-
微信头像加载细节:通过授权获取到的微信头像url是不包含格式后缀的,如果不声明加载文件类型就达不到预期的目的,所以在加载的时候需要添加文件的类型。
cc.loader.load({url: avatarUrl, type: 'png'}, (err, texture) => { if (err) { return cc.log(err); } let sp: cc.SpriteFrame = new cc.SpriteFrame(texture); this.imgHead.getComponent(cc.Sprite).spriteFrame = sp; });
-
代码动态改变图片精灵为九宫格model: 话不多说,直接上代码。
let Sprite = new cc.Sprite(); let sp = Sprite.spriteFrame; Sprite.type = cc.Sprite.Type.SLICED; // 纹理的四个边距 sp.insetBottom = 0; sp.insetTop = 0; sp.insetLeft = 0; sp.insetRight = 0;
-
微信加载子包代码:由于现在我参与的项目偏重度,资源以及代码量比较巨大,所以需要用到分包加载,分包加载的详细流程官方文档里面也说得比较详细,我这里就放一部分代码,仅供参考。
cc.loader.downloader.loadSubpackage('sub-package', function (err) { if (err) { return console.error(err); } console.log('load subpackage successfully.'); wxDownloader.init(); window.boot(); });
-
IOS微信小游戏,切后台然后重回游戏,会存在背景音乐不恢复播放的问题,解决方法:监听音乐中断事件,然后手动重新播放。
window['wx'].onAudioInterruptionEnd(() => { Util.showToast('onAudioInterruptionEnd'); // do something to resume music Game.getInstance().eventDispatcher.dispatchEvent(EventConfig.EVT_WX_AUDIO_INTERUPTION_END); });
-
昵称截取:项目经常会遇到玩家昵称过长,如果全部显示的话,可能会让整个UI布局变得不美观,那么就会出现截取固定像素长度的昵称这个需求,如果只是简单的通过截取字符串的长度,那么那些昵称中包含数字和英文的玩家名字就会很短,那些昵称中包含微信表情的玩家昵称就会显示过长,那么截取最美观的方法就是按像素截取,通过判断字符的Unicode来区分数字、字母与汉字,一个汉字相当于2个字符的长度算,,截取昵称工具函数转载自麒麟子代码如下。
/** * * @param str 需要截取的字符串 * @param maxChars 保留最大汉字长度 * @param suffix 添加的后缀 注意,如果后缀不为Boolean(suffix) => false ,则要占用一个汉字的位置 */ static strClamp(str: string, maxChars: number, suffix?: any): string { let toCodePoint: Function = (unicodeSurrogates: string): any[] => { let result: any[] = []; let c: number = 0; let p: number = 0; let i: number = 0; while (i < unicodeSurrogates.length) { let pos: number = i; // 返回位置的字符的 Unicode 编码 c = unicodeSurrogates.charCodeAt(i++); if (c === 0xfe0f) { continue; } if (p) { // 计算4字节的unicode let value: number = (0x10000 + ((p - 0xD800) << 10) + (c - 0xDC00)); result.push({ v: value, pos: pos, }); p = 0; } else if (0xD800 <= c && c <= 0xDBFF) { // 如果unicode编码在oxD800-0xDBff之间,则需要与后一个字符放在一起 p = c; } else { // 如果是2字节,直接将码点转为对应的十六进制形式 result.push({ v: c, pos: pos }); } } return result; } // 汉字算两个长度 maxChars <<= 1; let codeArr: any[] = toCodePoint(str); let numChar: number = 0; let index: number = 0; for (let i = 0; i < codeArr.length; ++i) { let code: number = codeArr[i].v; let add: number = 1; if (code >= 128) { add = 2; } //如果超过了限制,则按上一个为准 if (numChar + add > maxChars) { break; } index = i; //累加 numChar += add; } if (codeArr.length - 1 === index) { return str; } let more: number = suffix ? 1 : 0; suffix = suffix ? suffix : '...'; return str.substring(0, codeArr[index - more].pos + 1) + suffix; }
二、优化的一些细节
- 分帧加载:当某个界面打开的时候一瞬间需要创建很多预制体的话,可以考虑开启多线程加载预制体,防止主线程被卡死,影响体验,具体实现代码如下,当然也可以使用ES6语法Generator 函数实现异步分帧加载。
for (let i = 0; i < length; i++) { this.scheduleOnce(() =>{ let item = cc.instantiate(this.prefab); // do init // 处理初始化完毕后的逻辑 if (i === length -1) { // do something } }, 0.01); }
-
动态修改定时器的Interval:在实际项目中会遇到很多需求,比如一个发射炮弹的enemy,会随着游戏时间或者分数的增长需要越射越快,这时候如果用schedule实现这个功能的话,那么该如何去动态改变定时器的间隔呢?通过查看Cocos Creator schedule的源码发现,如果当前回调函数已经绑定过定时器,那么你再次调用schedule时不会设置新的定时器,而是改变之前定时器的时间间隔。(注意:如果定时器内的回调函数运行时报错,则会一直在定时器这里无限循环)
if (timer && callback === timer._callback) { cc.log(1507, timer.getInterval(), interval) timer._interval = interval; return; }
资源的动态加载与释放
不积跬步无以至千里,通过项目实战学到的一些新东西和一些知识遗漏的地方,记录下来不仅能让自己以后再看的时候温故而知新, 也能让遇到类似问题的同学有一个新思路,菜是原罪,不断学习,才能变强~~~~共勉。