[LayaAirIDE 1.0]微信小游戏渲染开放域卡顿处理
注:
引擎版本:1.7.22(稍微低点的也是可以的,这个没测过。。)
2.0版本ui有开放域的控件,由于没推广,个人没用过,性能不知道如何,如果用过的人觉得官方的已经很好了,请无视该文档。。
代码示例在第四点,懒得看我啰嗦的文字的可直接跳到此处看示例。。
一、绘制开放域界面:
绘制界面基本都是大同小异,就是将sharedCanvas转成纹理再绘制到graphics上,这里推荐看下http://ask.layabox.com/question/15195这个文档,写的还算全面(虽说我不用,题外话)
二、如何有效的控制开放域界面的开关:
官方推荐的就是对上述的纹理设置其属性:.bitmap.alwaysChange = true;(可以将该属性理解为是否需要持续刷新纹理内容)
但是会出现一个问题——在安卓机上特卡,然后就有人说了需要定时将它设为false,但这不能根本解决问题。对于那种一次性的界面如“排行榜”等这样处理是可以的,且首次打开掉帧很严重没有根本解决;对于频繁刷新的界面如“下位即将超越的好友”等界面时,这种处理就不科学了,频繁的修改alwaysChange无法做到实时的刷新开放域界面,而且卡顿问题特严重。
三、解决方案:
1.从上述可以大致得出解决的方案:(1)减少开放域界面的渲染频率(重点);(2)一次性界面定时关闭渲染。
2.减少开放域界面的渲染频率:
(1)启动定时器,每隔5帧刷新开放域界面——时间单位5帧是个人认为的一个合理数值,对于频繁刷新的界面再不济2个时间单位即10帧(0.1~0.2秒之间)必会显示出界面,这个时间间隔是可以接受的(因异步加载图片导致界面出来较慢不属于该范畴),在一般的安卓机频繁刷新的界面的帧数保持在40帧到50帧之间,这个帧数是可以接受的。
注:对于开放域有动画的界面(当然一般不会把动画放在开放域。。卡不死你),因为开放域界面5帧刷一次,相当于开放域的实际帧数只有12=60/5帧,对动画来说,看起来就不会很流畅了,因此可以稍微缩小时间单位。
(2)刷新开放域界面方法,即定时器的回调方法(重点):
function onTimer() {
// bitmap为纹理的bitmap属性,自行赋值
var func = bitmap._source && bitmap.reloadCanvasData;
func && func.call(bitmap);
}
3.关闭渲染:
个人认为5秒后停止定时器即可,因为使用了定时器去减缓渲染频率,因此这关闭就显得不是很重要,但是能尽量提高帧数还是要做的。这处理很简单,就是将定时器关了即可,不示范代码了。
四、代码示例(个人封装的开放域控件,TS版的,看不懂要JS版另外跟我说)
注:pfUtils是封装微信操作的工具类,这里我将下面用到的方法另外写出来,可自行替换成你们自己封装的方法。
// 开放域转纹理,这个没啥好说的,一般都是这么处理的
pfUtils.getShareCanvas = function() {
return new Laya.Texture(sharedCanvas/*window.sharedCanvas*/);
};
// 通知开放域数据:我这里采用的是“字符串标志+另外数据”来说明该指令是什么操作以及操作的参数,下面用到两个标识:enter进入或刷新开放域界面,携带界面标识viewName和宽高;exit退出开放域界面,携带界面标识viewName,开放域的界面创建、刷新和退出因人而异,可自行修改成你们自己想要的格式
pfUtils.postMessage = function(action: string, data?: any) {
var msg = {action, data};
wx.postMessage(msg);
};
// --------正式代码开始--------
module lie {
/**
* 微信数据开放域控件
* 使用:设置好控件大小、坐标及viewName即可,其它的无需管理(可在ui里拖入并设置好)
* 注:该控件跟开放域的代码是配套的,不同开放域代码请勿使用该类
*/
export class WXBitmap extends Laya.Sprite {
private $viewName: string;
private $texture: Laya.Texture;
private $bitmap: any;
private $timer: lie.Timer;
public auto: boolean = true; // 仅在未加入场景前修改有效,兼容ui
constructor() {
super();
this.once(Laya.Event.DISPLAY, this, this.onCreate);
this.once(Laya.Event.UNDISPLAY, this, this.onDestroy);
}
/**
* 加入场景
*/
protected onCreate(): void {
var self = this;
// 纹理
var texture = self.$texture = pfUtils.getShareCanvas();
var bitmap = self.$bitmap = texture.bitmap;
self.graphics.drawTexture(texture);
self.visible = false;
self.$timer = new Timer(self.reloadCanvas, self, 5, false, true);
self.auto && self.refresh();
}
/**
* 离开场景
*/
protected onDestroy(): void {
var self = this;
var post = pfUtils.postMessage;
self.clear();
post('exit', { view: self.$viewName });
// post('pause');
}
/**
* 设置界面名称
*/
public set viewName(value: string) {
this.$viewName = value;
}
/**
* 刷新开放域界面
* @param param 携带参数通知开放域
*/
public refresh(param?: any): void {
var self = this;
var width = self.width;
var height = self.height;
var data = {
view: self.$viewName,
width: width,
height: height
};
// 赋值属性
for (let i in param)
data[i] = param[i];
self.visible = true;
// 检测
var texture = self.$texture;
if (texture) {
let timer = self.$timer;
// 通知+延迟刷新界面
let post = pfUtils.postMessage;
// post('resume');
post('enter', data);
// 5秒后停止绘画
self.clearTimeout();
self.reloadCanvas(); // 先刷新一次
timer.start();
Laya.timer.once(5000, timer, timer.stop);
}
}
/**
* 重新渲染cavans界面
*/
protected reloadCanvas(): void {
var bitmap = this.$bitmap;
var func = bitmap._source && bitmap.reloadCanvasData;
func && func.call(bitmap);
}
/**
* 清除延迟
*/
protected clearTimeout(): void {
var self = this;
var timer = self.$timer;
Laya.timer.clear(timer, timer.stop);
}
/**
* 清除界面
*/
protected clear(): void {
var self = this;
var texture = self.$texture;
var timer = self.$timer;
if (timer) {
timer.clear();
self.$timer = null;
}
if (texture) {
texture.destroy(true);
self.$texture = null;
self.$bitmap = null;
}
self.clearTimeout();
self.graphics.clear();
}
}
}
// 由于官方的定时器用起来不是很舒服,自己封装的定时器,不想用可直接替换成Laya.timer.frameLoop来替代,请自行修改跟Timer相关代码。
module lie {
/**
* 定时器,可启动、停止及统计已运行时间(单位毫秒),默认启动
*/
export class Timer {
private $call: Function;
private $thisObj: any;
private $running: boolean;
private $runTime: number = 0; // 已运行时间
private $lastTime: number; // 上一次时间
/**
* 默认状态就是创建一个每一帧刷新一次的计时器
* @param call 回调方法
* @param thisObj 回调对象
* @param delay 延迟,默认1,isTime为true时表示毫秒,否则表示帧数
* @param isTime 是否时间回调,默认false(时间回调、帧回调)
* @param isStop 是否不需要直接运行
*/
public constructor(call: Function, thisObj?: any, delay: number = 1, isTime?: boolean, isStop?: boolean) {
this.$call = call;
this.$thisObj = thisObj;
isStop || this.start();
Laya.timer[isTime ? 'loop' : 'frameLoop'](delay, this, this.update);
}
/**
* 回调
*/
protected update(): void {
var self = this;
if (self.$running) {
self.$call.call(self.$thisObj);
}
}
/**
* 开始计时
*/
public start(): void {
var self = this;
if (!self.$running) {
self.$lastTime = Date.now();
self.$running = true;
}
}
/**
* 停止计时
*/
public stop(): void {
var self = this;
if (self.$running) {
let nowT = Date.now();
self.$runTime += nowT - self.$lastTime;
self.$lastTime = nowT;
self.$running = false;
}
}
/**
* 获取是否运行中
*/
public get running(): boolean {
return this.$running;
}
/**
* 获取运行的时间
*/
public get runTime(): number {
var self = this;
return self.$runTime + (self.running ?
Date.now() - self.$lastTime : 0);
}
/**
* 重置时间,归0
*/
public reset(): void {
var self = this;
self.$runTime = 0;
self.$lastTime = Date.now();
}
/**
* 清除定时器,一经清除,将不可再用
*/
public clear(): void {
var self = this;
Laya.timer.clear(self, self.update);
self.$call = self.$thisObj = null;
}
}
}
引擎版本:1.7.22(稍微低点的也是可以的,这个没测过。。)
2.0版本ui有开放域的控件,由于没推广,个人没用过,性能不知道如何,如果用过的人觉得官方的已经很好了,请无视该文档。。
代码示例在第四点,懒得看我啰嗦的文字的可直接跳到此处看示例。。
一、绘制开放域界面:
绘制界面基本都是大同小异,就是将sharedCanvas转成纹理再绘制到graphics上,这里推荐看下http://ask.layabox.com/question/15195这个文档,写的还算全面(虽说我不用,题外话)
二、如何有效的控制开放域界面的开关:
官方推荐的就是对上述的纹理设置其属性:.bitmap.alwaysChange = true;(可以将该属性理解为是否需要持续刷新纹理内容)
但是会出现一个问题——在安卓机上特卡,然后就有人说了需要定时将它设为false,但这不能根本解决问题。对于那种一次性的界面如“排行榜”等这样处理是可以的,且首次打开掉帧很严重没有根本解决;对于频繁刷新的界面如“下位即将超越的好友”等界面时,这种处理就不科学了,频繁的修改alwaysChange无法做到实时的刷新开放域界面,而且卡顿问题特严重。
三、解决方案:
1.从上述可以大致得出解决的方案:(1)减少开放域界面的渲染频率(重点);(2)一次性界面定时关闭渲染。
2.减少开放域界面的渲染频率:
(1)启动定时器,每隔5帧刷新开放域界面——时间单位5帧是个人认为的一个合理数值,对于频繁刷新的界面再不济2个时间单位即10帧(0.1~0.2秒之间)必会显示出界面,这个时间间隔是可以接受的(因异步加载图片导致界面出来较慢不属于该范畴),在一般的安卓机频繁刷新的界面的帧数保持在40帧到50帧之间,这个帧数是可以接受的。
注:对于开放域有动画的界面(当然一般不会把动画放在开放域。。卡不死你),因为开放域界面5帧刷一次,相当于开放域的实际帧数只有12=60/5帧,对动画来说,看起来就不会很流畅了,因此可以稍微缩小时间单位。
(2)刷新开放域界面方法,即定时器的回调方法(重点):
function onTimer() {
// bitmap为纹理的bitmap属性,自行赋值
var func = bitmap._source && bitmap.reloadCanvasData;
func && func.call(bitmap);
}
3.关闭渲染:
个人认为5秒后停止定时器即可,因为使用了定时器去减缓渲染频率,因此这关闭就显得不是很重要,但是能尽量提高帧数还是要做的。这处理很简单,就是将定时器关了即可,不示范代码了。
四、代码示例(个人封装的开放域控件,TS版的,看不懂要JS版另外跟我说)
注:pfUtils是封装微信操作的工具类,这里我将下面用到的方法另外写出来,可自行替换成你们自己封装的方法。
// 开放域转纹理,这个没啥好说的,一般都是这么处理的
pfUtils.getShareCanvas = function() {
return new Laya.Texture(sharedCanvas/*window.sharedCanvas*/);
};
// 通知开放域数据:我这里采用的是“字符串标志+另外数据”来说明该指令是什么操作以及操作的参数,下面用到两个标识:enter进入或刷新开放域界面,携带界面标识viewName和宽高;exit退出开放域界面,携带界面标识viewName,开放域的界面创建、刷新和退出因人而异,可自行修改成你们自己想要的格式
pfUtils.postMessage = function(action: string, data?: any) {
var msg = {action, data};
wx.postMessage(msg);
};
// --------正式代码开始--------
module lie {
/**
* 微信数据开放域控件
* 使用:设置好控件大小、坐标及viewName即可,其它的无需管理(可在ui里拖入并设置好)
* 注:该控件跟开放域的代码是配套的,不同开放域代码请勿使用该类
*/
export class WXBitmap extends Laya.Sprite {
private $viewName: string;
private $texture: Laya.Texture;
private $bitmap: any;
private $timer: lie.Timer;
public auto: boolean = true; // 仅在未加入场景前修改有效,兼容ui
constructor() {
super();
this.once(Laya.Event.DISPLAY, this, this.onCreate);
this.once(Laya.Event.UNDISPLAY, this, this.onDestroy);
}
/**
* 加入场景
*/
protected onCreate(): void {
var self = this;
// 纹理
var texture = self.$texture = pfUtils.getShareCanvas();
var bitmap = self.$bitmap = texture.bitmap;
self.graphics.drawTexture(texture);
self.visible = false;
self.$timer = new Timer(self.reloadCanvas, self, 5, false, true);
self.auto && self.refresh();
}
/**
* 离开场景
*/
protected onDestroy(): void {
var self = this;
var post = pfUtils.postMessage;
self.clear();
post('exit', { view: self.$viewName });
// post('pause');
}
/**
* 设置界面名称
*/
public set viewName(value: string) {
this.$viewName = value;
}
/**
* 刷新开放域界面
* @param param 携带参数通知开放域
*/
public refresh(param?: any): void {
var self = this;
var width = self.width;
var height = self.height;
var data = {
view: self.$viewName,
width: width,
height: height
};
// 赋值属性
for (let i in param)
data[i] = param[i];
self.visible = true;
// 检测
var texture = self.$texture;
if (texture) {
let timer = self.$timer;
// 通知+延迟刷新界面
let post = pfUtils.postMessage;
// post('resume');
post('enter', data);
// 5秒后停止绘画
self.clearTimeout();
self.reloadCanvas(); // 先刷新一次
timer.start();
Laya.timer.once(5000, timer, timer.stop);
}
}
/**
* 重新渲染cavans界面
*/
protected reloadCanvas(): void {
var bitmap = this.$bitmap;
var func = bitmap._source && bitmap.reloadCanvasData;
func && func.call(bitmap);
}
/**
* 清除延迟
*/
protected clearTimeout(): void {
var self = this;
var timer = self.$timer;
Laya.timer.clear(timer, timer.stop);
}
/**
* 清除界面
*/
protected clear(): void {
var self = this;
var texture = self.$texture;
var timer = self.$timer;
if (timer) {
timer.clear();
self.$timer = null;
}
if (texture) {
texture.destroy(true);
self.$texture = null;
self.$bitmap = null;
}
self.clearTimeout();
self.graphics.clear();
}
}
}
// 由于官方的定时器用起来不是很舒服,自己封装的定时器,不想用可直接替换成Laya.timer.frameLoop来替代,请自行修改跟Timer相关代码。
module lie {
/**
* 定时器,可启动、停止及统计已运行时间(单位毫秒),默认启动
*/
export class Timer {
private $call: Function;
private $thisObj: any;
private $running: boolean;
private $runTime: number = 0; // 已运行时间
private $lastTime: number; // 上一次时间
/**
* 默认状态就是创建一个每一帧刷新一次的计时器
* @param call 回调方法
* @param thisObj 回调对象
* @param delay 延迟,默认1,isTime为true时表示毫秒,否则表示帧数
* @param isTime 是否时间回调,默认false(时间回调、帧回调)
* @param isStop 是否不需要直接运行
*/
public constructor(call: Function, thisObj?: any, delay: number = 1, isTime?: boolean, isStop?: boolean) {
this.$call = call;
this.$thisObj = thisObj;
isStop || this.start();
Laya.timer[isTime ? 'loop' : 'frameLoop'](delay, this, this.update);
}
/**
* 回调
*/
protected update(): void {
var self = this;
if (self.$running) {
self.$call.call(self.$thisObj);
}
}
/**
* 开始计时
*/
public start(): void {
var self = this;
if (!self.$running) {
self.$lastTime = Date.now();
self.$running = true;
}
}
/**
* 停止计时
*/
public stop(): void {
var self = this;
if (self.$running) {
let nowT = Date.now();
self.$runTime += nowT - self.$lastTime;
self.$lastTime = nowT;
self.$running = false;
}
}
/**
* 获取是否运行中
*/
public get running(): boolean {
return this.$running;
}
/**
* 获取运行的时间
*/
public get runTime(): number {
var self = this;
return self.$runTime + (self.running ?
Date.now() - self.$lastTime : 0);
}
/**
* 重置时间,归0
*/
public reset(): void {
var self = this;
self.$runTime = 0;
self.$lastTime = Date.now();
}
/**
* 清除定时器,一经清除,将不可再用
*/
public clear(): void {
var self = this;
Laya.timer.clear(self, self.update);
self.$call = self.$thisObj = null;
}
}
}
没有找到相关结果
已邀请:
要回复问题请先登录
2 个回复
Aar0n
赞同来自:
zhangdiansong
赞同来自: