请教一个渲染的问题

为什么在一段程序中改变了组件的纹理,要到程序结束后才能渲染出来?而在计时器中执行就能立刻渲染?

什么叫程序结束后才能渲染出来?

           比如   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

1赞

明白了,谢谢!我一直用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);
        }
    }
1赞

好耐心,点赞

是的,这个方法我也试过,这只是个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)添加一盏灯到灯队列里面,就可以了。