为什么在一段程序中改变了组件的纹理,要到程序结束后才能渲染出来?而在计时器中执行就能立刻渲染?
什么叫程序结束后才能渲染出来?
比如 case cc.KEY.s:
self.Demo.demoStart();
demoStart: function() {
//
sprite1.spriteFrame = frame[0]; //这时组件纹理没改变
…
…
sprite2.spriteFrame = frame[0]; //这时组件纹理也没改变
return; //返回后纹理改变了。
},
好像是要从用户程序返回后才能渲染, 组件在程序中的渲染过程就看不到。有否办法在组件改变后立刻渲染?
demoStart: function() {
//
sprite.spriteFrame = texture1;
… //纹理没有渲染
…
sprite.spriteFrame = texture2;
…//纹理没有渲染
…
return; //返回后纹理改变了,这样就显示不出纹理从texture1到texture2的改变。
},
如果你的代码是在同一帧内执行的,操作结果到下一帧才会渲染。
但我的代码中有很多连续改变贴图的地方,难道要把代码分割在多个帧上执行,又怎样在下一帧时执行下一条语句?另外一个问题,update function(dt)是同步还是异步执行?
连续改变贴图,肯定有一个让玩家能看到的时间吧?同一帧内改变肯定是看不了的。假如你有多个texture存在this.textures数组中,你可以用schedule定时(比如每0.1秒)切换一次贴图,切完所有textures后unschedule;或者也可以用一个变量记录当前是第几个贴图(比如开始时this.textureIndex=0代表第一个贴图),然后在update函数里判断if (this.texturesIndex < this.textures.length - 1)则this.textureIndex++;加载下一个贴图。update是异步的。
//game.js
demoStart: function(){
common.num = 0;
common.flagLight = true;
console.log('这个是第一盏灯' + 0);
common.num = 1;
common.flagLight = true;
console.log('这个是第二盏灯' + 1);
common.num = 2;
common.flagLight = true;
console.log('这个是第三盏灯' + 2);
},
update: function (dt) {
common.onLeds();
},
//common.js
onLeds: function(){
if(this.flagLight)
{
this.light(this.num);
console.log(‘这个是第一亮灯’ + this.num);
//~this.flagLight;
}
},
如果update是异步的,那结果就应该这样:
Simulator: 这个是第一盏灯0
Simulator: 这个是第一亮灯0
Simulator: 这个是第二盏灯1
Simulator: 这个是第一亮灯1
Simulator: 这个是第三盏灯2
Simulator: 这个是第一亮灯2
但现在的结果却是这样:
你对Javascript的异步概念理解错了。JS引擎是单线程的,JS中所谓的异步只不过是不同任务排好队(允许插队)等待引擎去同步执行而已,同一时间只会执行你的一段代码。你的demoStart和update是不会同时执行的。但是你基本上都可以通过schedule()去模拟你想要的多线程异步。百度了一篇JS异步机制的文章给你:
http://www.cnblogs.com/zhaodongyu/p/3922961.html
明白了,谢谢!我一直用C++搞开发,才学习js,对它的异步理解有误。看来js中不能用到精确定时的。另外用schedule()模拟还是不行,结果与update()一样。
用C++也是一样的,openGL只能单线程,贴图改变怎么都是单线程的。
schedule定时改变贴图应该是可以的,把你的schedule代码发来看看呗。代码前后用三个`(键盘数字1前面那个键)包起来,论坛会格式化你的代码。
demoStart: function(){
common.num = 0;
this.schedule(common.onLeds);
console.log('这个是第一盏灯' + 0);
common.delay();
common.num = 1;
this.schedule(common.onLeds);
console.log('这个是第二盏灯' + 1);
common.delay();
common.num = 2;
this.schedule(common.onLeds);;
console.log('这个是第三盏灯' + 2);
common.delay();
},
//common.js
var obj = this;
delay: function() {
var i = 100000;
while(i != 0) {i--; }
},
onLeds: function(){
obj.light(obj.num);
console.log('这个是第一亮灯' + obj.num);
},
你用循环阻塞线程也还是在同一帧。
试一下:
demoStart: function() {
var interval = 2; // 假设2秒切换下一盏灯,你可以设定为0.1之类的
common.num = 0; // 初始加载第0盏
this.schedule(this.nextLed, interval);
// 如果第一帧就要加载灯的话,在这里执行一次this.nextLed();否则会在interval后加载第一个灯
},
nextLed: function() {
common.onLeds();
common.num++;
console.log("这个是第" + common.num + "盏灯");
// 若已经亮了3盏灯,则取消schedule
if (common.num >= 3) {
this.unschedule(this.nextLed);
}
}
好耐心,点赞
是的,这个方法我也试过,这只是个demo,而实际的代码复杂得多,亮两个灯之间还有很多代码,其中有些亮灯在for循环中,demoStart中的子函数中也有,这样用schedule一层层调下去只有晕菜了。不知引擎中也没渲染的函数?在onLeds后,立刻控制渲染。
你的每次亮灯,都必须让玩家看到是吗?亮的时间是多久?1帧?
是的,就像流水灯,有样式变化。不是一帧,要清晰的看到。
不用多个schedule。你把要切换的灯想像成一个队列,每隔0.1秒检查一下这个队列有没有未显示的灯,有的话显示出来。
demoStart: function() {
var interval = 0.1; // 0.1秒检查一次
common.lights = []; // 初始灯的队列数组,假设还没有灯
common.num = 0; // 初始加载第0盏
this.schedule(this.nextLed, interval);
// 如果第一帧就要加载灯的话,在这里执行一次this.nextLed();否则会在interval后加载第一个灯
},
nextLed: function() {
// 如果当前要加载的灯(common.num),在灯数组中存在
if (common.num < common.lights.length) {
// 点亮这盏灯
common.onLeds();
// 准备点亮下一盏灯
common.num++;
console.log("这个是第" + common.num + "盏灯");
}
}
这样这个schedule就会每0.1秒检查一次你的common.lights,你要做的就是在你代码中任何想亮灯的地方,common.lights.push(light)添加一盏灯到灯队列里面,就可以了。
